Compare two Arrays in KSH and output the difference

5,242

You get an error because you're attempting to do arithmetic equality with string values.

Here are 2 ways to check whether the elements of dfArray are in dsmArray

set -A dfArray / /usr /var /tmp ...
set -A dsmArray /home /opt /usr ...

for a in "${dfArray[@]}"; do
  in=false
  for b in "${dsmArray[@]}"; do
    if [[ $a == $b ]]; then
      echo "$a is in dsmArray"
      in=true
      break
    fi
  done
  $in || echo "$a is not in dsmArray"
done
/ is not in dsmArray
/usr is in dsmArray
/var is not in dsmArray
/tmp is not in dsmArray
... is in dsmArray

Or, flattening the dsmArray and avoiding the inner loop:

for a in "${dfArray[@]}"; do
  # all quotes and spaces required below
  if [[ " ${dsmArray[*]} " == *" $a "* ]]; then
    echo "$a is in dsmArray"
  else
    echo "$a is not in dsmArray"
  fi
done
/ is not in dsmArray
/usr is in dsmArray
/var is not in dsmArray
/tmp is not in dsmArray
... is in dsmArray

This solution keys on this part: [[ " ${dsmArray[*]} " == *" $a "* ]]

  1. " ${dsmArray[*]} "
    • when quoted, "${ary[*]}" results in a single string composed of the individual elements of the array joined on the first character of $IFS
    • the default of $IFS is 3 characters: space, tab, newline
    • with the leading and trailing quotes, we get the string " /home /opt /usr ... "
  2. *" $a "*
    • inside double brackets, the == operator is actually a pattern matching operator, not strictly equality
    • our pattern is:
      • zero or more characters, followed by
      • a space, followed by
      • the value of $a, followed by
      • a space, followed by
      • zero or more characters

So, for each value of dfArray, we are checking to see if it appears as a space-separated word within the flattened dsmArray string.

This breaks down with the array elements can contain spaces. Then you need to assign a new value to IFS and things get messy(-er).


To get an array of common elements, I'd do

typeset -i n=0
set -A common
for a in "${dfArray[@]}"; do
  if [[ " ${dsmArray[*]} " == *" $a "* ]]; then
    let n+=1
    common[n]=$a
  fi
done

echo "common"
printf "%s\n" "${common[@]}"
echo "common with index"
typeset -i i=1
while (( i <= n )); do echo "$i  ${common[i]}"; ((i+=1)); done
common
/usr
...
common with index
1  /usr
2  ...
Share:
5,242

Related videos on Youtube

Christopher Stanley
Author by

Christopher Stanley

Updated on September 18, 2022

Comments

  • Christopher Stanley
    Christopher Stanley over 1 year

    I am not extremely familiar with KSH (Actually just started using it) and I am having problems with trying to create a script that will essentially compare two arrays that have been stored and then output the difference.

    Running AIX 6.1 with KSH Version M-11/16/88f

    Here is what I have thus far:

    #!/bin/ksh
    set -A dfArray $(df | awk '{print $7}' | grep -v Mounted)
    set -A dsmArray $(cat dsm.sys | grep DOMAIN | awk '{ s=""; for (i = 2; i <= NF; i++) s = s $i " "; print s }')
    
    MAX=$((${#dsmArray[*]}-1))
    
    for a in ${dfArray[*]}
           do
           COUNT=0
           set -A UNMATCHED
           for b in ${dsmArray[*]}
                   do
                   (( $a != $b )) && \
                   UNMATCHED[$COUNT]=$a && \
                   let COUNT+=1
           done
           (( ${#UNMATCHED[*]} != $MAX )) && \
           print ${UNMATCHED[0]}
           unset UNMATCHED
    done
    

    Here are what the two arrays might look like: dfArray:

    /
    /usr
    /var
    /tmp
    ...
    

    dsmArray:

    /home
    /opt
    /usr
    ...
    

    When I run the current script I get the following error:

    ./checkBackup.sh[22]:  / != /home : syntax error
    

    What am I doing wrong? I am sure it's probably something simple.

    Thanks!

  • Christopher Stanley
    Christopher Stanley over 9 years
    Ahh, duh - That was a silly mistake. Your solution worked perfectly for me. Thanks for your help! Could you explain what is going on when you flatten the dsmArray? I understand your first solution with the nested for statements. Trying to understand your second solution.
  • Angel Todorov
    Angel Todorov over 9 years
    Oh, there's actually an error there, need " ${dsmArray[*]} " -- explanation will be in answer
  • Christopher Stanley
    Christopher Stanley over 9 years
    It would appear that ${dfArray[@]} worked too. Is this expected?
  • Christopher Stanley
    Christopher Stanley over 9 years
    In fact, changing it to ${dfArray[*]} causes it to output everything, not just the differences.
  • Angel Todorov
    Angel Todorov over 9 years
    I wouldn't have thought so, but I guess the double brackets do some magical things. You can see how the two array expansions differ: print ">%s<\n" " ${dsmArray[*]} " versus print ">%s<\n" " ${dsmArray[@]} "
  • Christopher Stanley
    Christopher Stanley over 9 years
    Alright, well the print command on both of those arrays with * and @ output the same thing. Since using [@] on both works for me I will keep it like that. Just was curious as to why, guess I wont question it :P Thanks again for your help!