我试图使用grep
仅显示包含两个单词中的任何一个的行,如果其中一个出现在行中,但如果它们在同一行中则不显示。
到目前为止,我已经尝试过, grep pattern1 | grep pattern2 | ...
但没有得到我预期的结果。
Chr*_*ris 61
其他工具grep
是要走的路。
例如,使用 perl,命令将是:
perl -ne 'print if /pattern1/ xor /pattern2/'
Run Code Online (Sandbox Code Playgroud)
perl -ne
在 stdin 的每一行上运行给定的命令,在这种情况下,如果它匹配/pattern1/ xor /pattern2/
,则打印该行,或者换句话说,匹配一个模式但不匹配另一个(异或)。
这适用于任一顺序的模式,并且应该比多次调用 具有更好的性能grep
,并且输入也更少。
或者,甚至更短,使用 awk:
awk 'xor(/pattern1/,/pattern2/)'
Run Code Online (Sandbox Code Playgroud)
或者对于没有的 awk 版本xor
:
awk '/pattern1/+/pattern2/==1`
Run Code Online (Sandbox Code Playgroud)
Hax*_*iel 31
使用 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
Run Code Online (Sandbox Code Playgroud)
Siv*_*iva 17
试试 egrep
egrep 'pattern1|pattern2' file | grep -v -e 'pattern1.*pattern2' -e 'pattern2.*pattern1'
Run Code Online (Sandbox Code Playgroud)
Sté*_*las 12
使用grep
支持类似 perl 的正则表达式(如pcregrep
或 GNU 或 ast-open grep -P
)的实现,您可以在一次grep
调用中使用:
grep -P '^(?=.*pat1)(?!.*pat2)|^(?=.*pat2)(?!.*pat1)'
Run Code Online (Sandbox Code Playgroud)
即找到匹配pat1
但不匹配pat2
或pat2
不匹配的行pat1
。
(?=...)
和(?!...)
分别是前瞻和负前瞻运算符。因此,从技术上讲,上面的内容查找主题 ( ^
)的开头,前提是它后跟.*pat1
而不是后跟.*pat2
,或者与pat1
和pat2
反转相同。
这对于包含两种模式的行来说是次优的,因为它们会被查找两次。您可以改为使用更高级的 perl 运算符,例如:
grep -P '^(?=.*pat1|())(?(1)(?=.*pat2)|(?!.*pat2))'
Run Code Online (Sandbox Code Playgroud)
(?(1)yespattern|nopattern)
针对匹配yespattern
,如果1
第一捕获组(空()
上文)相匹配,并nopattern
以其他方式。如果()
匹配,这意味着pat1
不匹配,所以我们寻找pat2
(正前方看),我们期待的不是 pat2
否则(负前瞻)。
用sed
,你可以这样写:
sed -ne '/pat1/{/pat2/!p;d;}' -e '/pat2/p'
Run Code Online (Sandbox Code Playgroud)