Home > Software design >  How do I see if the output of one command is in the output of another?
How do I see if the output of one command is in the output of another?

Time:09-16

I have two commands. The first, when stored in a script variable, gives output like this:

one two three four five

The second also gives a list, but some of the items may be missing that were in the first command:

one three five

I want my script to do something if an item is in the first command but not the second. None of the items will have spaces (they tend to be kabab-format). How can I do this in Bash?

CodePudding user response:

Regarding my comment [1], I'd tackle this like following:

#!/bin/bash

res1=(one two three four five)
res2=(one three five)

for value in "${res1[@]}"; do
    if [[ ! "${res2[*]}" =~ "${value}" ]]; then

        # Do action
        echo "'$value' does not exist in res2"

        # Possibly stop for loop
        break
    fi
done

With the break, this will show:

'two' does not exist in res2

Without the break, it will show:

'two' does not exist in res2
'four' does not exist in res2

CodePudding user response:

One approach using the current variables, and relying on the fact that individual values do not contain embedded white space:

$ var1='one two three four five'
$ var2='one three five'
$ comm -23 <(printf "%s\n" ${var1} | sort) <(printf "%s\n" ${var2} | sort)
four
two

NOTE: do not wrap the ${var1} and ${var2} references in double quotes, ie, we want word splitting to occur when feeding the printf calls


Another idea using an associative array to track unique values:

var1='one two three four five'
var2='one three five'

unset      arr
declare -A arr

for f in ${var1}          # use ${var1} values as indices for arr[]
do
    arr[${f}]=1           # '1' has no meaning other than to fill requirement of assigning a value in order to create the array entry
done

for f in ${var2}          # delete ${var2} indices from arr[]
do
    unset arr[${f}]
done


for i in "${!arr[@]}"     # display arr[] indices that remain
do
    echo "${i}"
done

# one-liners (sans comments)

for f in ${var1}; do arr[${f}]=1; done
for f in ${var2}; do unset arr[${f}]; done
for i in "${!arr[@]}"; do echo "${i}"; done

This generates:

two
four

NOTES:

  • again, do not wrap the ${var1} and ${var2} references in double quotes, ie, we want word splitting to occur
  • if so inclined OP could perform the same add/remove array operations in a single awk script
  • the first loop (populating arr[] from ${var1}) will eliminate duplicates from ${var1}, eg, var1='one one one' would lead to a single array entry: arr[one]=1
  • Related