I prefer `awk` over `uniq` and `comm` because awk tends to be faster at set ops that can skip sorting and deduplicating.
Here's my script for union, intersection, etc. See README on GitHub. Suggestions welcome.
https://github.com/sixarm/setop
#!/bin/sh
set -eu
op="$1"; shift
case $op in
∪|u|union|or|∨|add|addition|'+'|'|')
awk '!seen[$0] {print} {seen[$0]=1}' "$@"
;;
∩|i|intersection|and|∧|'&')
awk 'FNR==1{argind+=1} seen[$0]+=1 {next} END { for (key in seen) { if (seen[key]==argind) { print key } } }' "$@"
;;
⊖|d|diff|difference|xor|⊻)
awk 'FNR==1{argind+=1} seen[$0]+=1 {next} END { for (key in seen) { if (seen[key]==1) { print key } } }' "$@"
;;
ex|except|exclude|subtract|subtraction|'-')
awk 'NR==FNR{seen[$0]=1;next} seen[$0]=0; END { for (key in seen) { if (seen[key]) { print key } } }' "$@"
;;
extra)
awk 'BEGIN{argindmax=ARGC-1} FNR==1{argind+=1} argind<argindmax {seen[$0]; next}!($0 in seen)' "$@"
;;
disjoint|n|not|none)
awk 'seen[$0]==1 {x=1;exit} {seen[$0]=1} END { print x ? "FALSE" : "TRUE"}; exit !!x}' "$@"
;;
*)
esac