Answers:
除行之有效的工具外,还有其他工具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`
xor
-Awk仅在GNU Awk中可用吗?
/pattern1/+/pattern2/==1
ir xor
缺少。
\b
在模式本身(即)中添加单词边界()\bword\b
。
试试看 egrep
egrep 'pattern1|pattern2' file | grep -v -e 'pattern1.*pattern2' -e 'pattern2.*pattern1'
grep -e foo -e bar | grep -v -e 'foo.*bar' -e 'bar.*foo'
Direct invocation as either egrep or fgrep is deprecated
-更喜欢grep -E
grep
(即支撑件-F
,-E
,-e
,-f
如POSIX要求)是/usr/xpg4/bin
。中的实用程序/bin
是过时的。
使用grep
支持类似perl的正则表达式(例如pcregrep
,GNU或ast-open grep -P
)的实现,您可以grep
通过以下方法一次调用:
grep -P '^(?=.*pat1)(?!.*pat2)|^(?=.*pat2)(?!.*pat1)'
这是找到匹配的线pat1
,但没有pat2
,或pat2
而不是pat1
。
(?=...)
和(?!...)
分别是前瞻性经营者和消极前瞻性经营者。因此,从技术上讲,上面的内容查找的是主题(^
)的开头,前提是该主题后面紧跟着(.*pat1
而不是紧跟着).*pat2
,或者带有pat1
和pat2
颠倒了。
对于同时包含两种模式的行而言,这不是最佳选择,因为随后将对其进行两次查找。您可以改用更高级的perl运算符,例如:
grep -P '^(?=.*pat1|())(?(1)(?=.*pat2)|(?!.*pat2))'
(?(1)yespattern|nopattern)
匹配yespattern
是否1
第一捕获组(空()
上文)相匹配,并nopattern
以其他方式。如果()
匹配,则表示pat1
不匹配,因此我们寻找pat2
(正向看),否则寻找不 pat2
(负向看)。
使用sed
,您可以编写它:
sed -ne '/pat1/{/pat2/!p;d;}' -e '/pat2/p'
grep: the -P option only supports a single pattern
,至少在我可以访问的每个系统上都没有。不过,您可以为第二个解决方案+1。
grep
。pcregrep
和ast-open grep没有这个问题。我已经用-e
替代RE运算符替换了倍数,因此它grep
现在也应该与GNU一起使用。
用布尔术语,您正在寻找A xor B,可以写成
(A而不是B)
要么
(B,而不是A)
只要您的问题没有提到只要显示匹配的行,您就关心输出的顺序,那么在grep中,A xor B的布尔扩展非常简单:
$ 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
sort | uniq
。
对于以下示例:
# Patterns:
# apple
# pear
# Example line
line="a_apple_apple_pear_a"
这完全可以利用来完成grep -E
,uniq
和wc
。
# Grep for regex pattern, sort as unique, and count the number of lines
result=$(grep -oE 'apple|pear' <<< $line | sort -u | wc -l)
如果grep
使用Perl正则表达式编译,则可以在最后一次出现时进行匹配,而无需通过管道传递给uniq
:
# Grep for regex pattern and count the number of lines
result=$(grep -oP '(apple(?!.*apple)|pear(?!.*pear))' <<< $line | wc -l)
输出结果:
# Only one of the words exists if the result is < 2
((result > 0)) &&
if (($result < 2)); then
echo Only one word matched
else
echo Both words matched
fi
单线:
(($(grep -oP '(apple(?!.*apple)|pear(?!.*pear))' <<< $line | wc -l) == 1)) && echo Only one word matched
如果您不想对模式进行硬编码,则可以使用函数自动将其与可变的元素集组装在一起。
也可以在Bash中将其作为函数来完成,而无需使用管道或其他进程,但会涉及更多问题,并且可能不在您的问题范围内。
Big apple\n
和pear-shaped\n
,则输出应包含这两行。您的解决方案将获得2分;长版本将报告“两个单词都匹配”(这是对错误问题的答案),而短版本将什么也没有说。(3)一条建议:使用-o
此处是一个非常糟糕的主意,因为它隐藏了包含匹配项的行,因此您看不到两个单词何时出现在同一行。…(续)
uniq
/ sort -u
和花哨的Perl正则表达式仅匹配每行的最后一个出现并没有真正为该问题提供有用的答案。但是,即使他们做了,这仍然是一个不好的答案,因为您没有解释他们如何对回答问题做出贡献。(请参阅StéphaneChazelas的答案以作一个很好的解释的例子。)
[a-z][a-z0-9]\(,7\}\(\.[a-z0-9]\{,3\}\)+
?(2)如果一个单词/模式在一行中出现多次(又不出现)怎么办?那等于一个单词出现一次,还是算作多次出现?