1

I have 2 lists

list1=( "Arwen Hagan" "Catriona Hutton" "Sasha Tucker" "Virgil Mcdowell" )
list2=( "Arwen Hagan" "Catriona Hutton" )

I want list1 - list2 to return a new list like this:

final=( "Sasha Tucker" "Virgil Mcdowell" )

My attempt

final=($(comm -3 <(printf "%s\n" "${list1[@]}" | sort) <(printf "%s\n" "${list2[@]}" | sort) | sort -n)) 
for val in "${listr[@]}"; do
  echo $val
done

Output

Sasha
Tucker
Virgil
Mcdowell

Expected Output

Sasha Tucker
Virgil Mcdowell
Cyrus
  • 84,225
  • 14
  • 89
  • 153
William
  • 1,107
  • 2
  • 11
  • 18

1 Answers1

1

You may use this single line mapfile + grep + printf solution:

mapfile -t final < <(grep -vxFf <(printf '%s\n' "${list2[@]}") <(printf '%s\n' "${list1[@]}"))

# check resulting array
declare -p final
declare -a final=([0]="Sasha Tucker" [1]="Virgil Mcdowell")

Here:

  • printf '%s\n' "${list2[@]}" prints each item in array on new line
  • <(printf '%s\n' "${list2[@]}") is process substitution to treat output of printf like a file
  • grep -vxFf file2 file1 will find entries in file1 that are not present in file2. Options used are: x - exact match, v - inverse match, F - fixed string search and f - use file for input pattern
anubhava
  • 761,203
  • 64
  • 569
  • 643