Reputation: 763
I have two strings:
l1='a1 a2 b1 b2 c1 c2'
l2='a1 b3 c1'
And I want to check if each element of string l2
exists in l1
, and then remove it from l1
.
Is it possible to do that without a for
loop?
Upvotes: 0
Views: 35
Reputation: 781814
You can do this:
l1=$(comm -23 <(echo "$l1" | tr ' ' '\n' | sort) <(echo "$l2" | tr ' ' '\n' | sort) | tr '\n' ' ')
The comm
compares lines and outputs the lines that are unique to the first input, unique to the second input, and common to both. The -23
option suppresses the second two sets of outputs, so it just reports the lines that are unique to the first input.
Since it requires the input to be sorted lines, I first pipe the variables to tr
to put each word on its own line, and then sort
to sort it. <(...)
is a common shell extension called process substitution that allows a command to be used where a filename is expected; it's available in bash
and zsh
, for example (see here for a table that lists which shells have it).
At the end I use tr
again to translate the newlines back to spaces.
If you don't have process substution, you can emulate it with named pipes:
mkfifo p1
echo "$l1" | tr ' ' '\n' | sort > p1 &
mkfifo p2
echo "$l2" | tr ' ' '\n' | sort > p2 &
l1=$(comm p1 p2 | tr '\n' ' ')
rm p1 p2
Upvotes: 1