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:
- Loop over
res1
- If current value does not exist in
res2
- Preform action
- Stop
for
if needed
- If current value does not exist in
#!/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