如何 grep 查找包含两个单词之一但不是同时包含两个单词的行?

如何 grep 查找包含两个单词之一但不是同时包含两个单词的行?

我试图用来grep仅显示包含这两个单词中的任何一个的行,如果它们中只有一个出现在行中,但如果它们在同一行中则不显示。

到目前为止,我已经尝试过, grep pattern1 | grep pattern2 | ...但没有得到我预期的结果。

答案1

除此以外的工具grep才是出路。

例如,使用 perl,命令将是:

perl -ne 'print if /pattern1/ xor /pattern2/'

perl -ne运行对 stdin 的每一行给出的命令,在本例中,如果匹配 ,则打印该行/pattern1/ xor /pattern2/,或者换句话说,匹配一个模式但不匹配另一个模式(异或)。

这适用于任一顺序的模式,并且应该比多次调用 , 具有更好的性能grep,并且打字也更少。

或者,更短,使用 awk:

awk 'xor(/pattern1/,/pattern2/)'

或者对于没有的 awk 版本xor

awk '/pattern1/+/pattern2/==1`

答案2

使用 GNU grep,您可以将两个单词传递给grep然后删除包含这两个模式的行。

$ cat testfile.txt
abc
def
abc def
abc 123 def
1234
5678
1234 def abc
def abc

$ grep -w -e 'abc' -e 'def' testfile.txt | grep -v -e 'abc.*def' -e 'def.*abc'
abc
def

答案3

尝试用egrep

egrep  'pattern1|pattern2' file | grep -v -e 'pattern1.*pattern2' -e 'pattern2.*pattern1'

答案4

用布尔术语来说,您正在寻找 A xor B,它可以写为

(A 而不是 B)

或者

(B 而不是 A)

鉴于您的问题没有提到您关心输出的顺序,只要显示匹配行,A xor B 的布尔扩展在 grep 中就非常简单:

$ cat << EOF > foo
> a b
> a
> b
> c a
> c b
> b a
> b c
> EOF
$ grep -w 'a' foo | grep -vw 'b'; grep -w 'b' foo | grep -vw 'a';
a
c a
b
c b
b c

相关内容