I need some help with displaying all lines that don't contain word1
or word2
but lines that contain both of them have to be shown.
Example:
aaaa bbbb cccc
bbbb bbbb bbbb
cccc cccc cccc
dddd dddd aaaa
if word1 = aaaa
and word2 = bbbb
then output should be:
aaaa bbbb cccc
cccc cccc cccc
Tried
grep -Ewv "word1/word2" file.txt
but this shows only lines that don't contain them, it doesn't show lines containing both
I need to do this with grep command, forgot to mention this
Grep version of both or none of each:
grep -v -P '((?=.*aaaa)(?!.*bbbb))|((?=.*bbbb)(?!.*aaaa))'
But please do not use grep
in this case. Negative and positive look ahead can easily lead to Catastrophic Backtracking
GNU grep
knows Perl compatible regular expression (PCRE) syntax (option -P
). This thing is still called a "regular" expression, although it not regular anymore. Other people are more explicit and call backtracking irregular expressions.
How it works:
(?=.*aaaa)
matches aaaa
anywhere in the line, but does not move the cursor. After the match the next search starts at the beginning of the line.
(?..*bbbb)
matches when no bbbb
is in the line and does not move the cursor either.
Both together matches lines, which include aaaa
but do not include bbbb
.
This is one of the cases you want to exclude, from your search results. The second behind the or condition ( |
) is the other one you want to exclude: any bbbb
without a aaaa
.
With the above, you have defined, what you do not want. Next use -v
to invert the search to get what you want.
Bash version of both or none of each:
#! /bin/bash
word1=${1:-aaaa}
word2=${2:-bbbb}
while read -r line; do
if [[ $line =~ $word1 ]]; then
if [[ $line =~ $word2 ]]; then
printf "%s\n" "$line"
fi
else
if [[ $line =~ $word2 ]]; then
:
else
printf "%s\n" "$line"
fi
fi
done
In my opinion, the simplest way (even though possibly not the fastest) is to find separately the lines that contain neither word and the lines that contain both words, and to concatenate the results. For example (assuming file.txt
is a text file in directory test
, and I pass the input values as environment variables for generality - and we are only looking for full words, not word fragments):
[mathguy@localhost test]$ more file.txt
aaaa bbbb cccc
bbbb bbbb bbbb
cccc cccc cccc
dddd dddd aaaa
[mathguy@localhost test]$ word1=aaaa
[mathguy@localhost test]$ word2=bbbb
[mathguy@localhost test]$ ( grep "\b$word1\b" file.txt | grep "\b$word2\b" ; \
> grep -v "\b$word1\b" file.txt | grep -v "\b$word2\b" ) | cat
aaaa bbbb cccc
cccc cccc cccc
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.