Bash set subtraction

Viewed 9039

How to subtract a set from another in Bash?

This is similar to: Is there a "set" data structure in bash? but different as it asks how to perform the subtraction, with code

  • set1: N lines as output by a filter
  • set2: M lines as output by a filter

how to get:

  • set3: with all lines in N which don't appear in M
5 Answers

I've got a dead-simple 1-liner:

$ now=(ConfigQC DBScripts DRE DataUpload WFAdaptors.log)

$ later=(ConfigQC DBScripts DRE DataUpload WFAdaptors.log baz foo)

$ printf "%s\n" $now $later | sort | uniq -c | grep -vE '[ ]+2.*' | awk '{print $2}'
baz
foo

By definition, 2 sets intersect if they have elements in common. In this case, there are 2 sets, so any count of 2 is an intersection - simply "subtract" them with grep

You can use diff

# you should sort the output
ls > t1
cp t1 t2

I used vi to remove some entries from t2

$ cat t1
AEDWIP.writeMappings.sam
createTmpFile.sh*
find.out
grepMappingRate.sh*
salmonUnmapped.sh*
selectUnmappedReadsFromFastq.sh*

$ cat t2
AEDWIP.writeMappings.sam
createTmpFile.sh*
salmonUnmapped.sh*
selectUnmappedReadsFromFastq.sh*

diff reports lines in t1 that are not in t2

diff t1 t2
$ diff t1 t2
3,4d2
< find.out
< grepMappingRate.sh*

putting together version

diff t1 t2 | grep "^<" | cut -d " " -f 2
find.out
grepMappingRate.sh*
Related