我有一个包含“then”和“there”的文件。
我可以
$ grep "then " x.x
x and then some
x and then some
x and then some
x and then some
我可以
$ grep "there " x.x
If there is no blob none some will be created
如何在一次操作中搜索两者?我试过
$ grep (then|there) x.x
-bash:意外标记“(”附近出现语法错误
和
grep "(then|there)" x.x
durrantm.../code
# (Nothing)
答案1
您需要将表达式放在引号中。您收到的错误是 bash 将 解释(
为特殊字符的结果。
另外,您需要告诉 grep 使用扩展正则表达式。
$ grep -E '(then|there)' x.x
如果没有扩展的正则表达式,您必须转义|
、(
和)
。请注意,我们在这里使用单引号。 Bash 特别对待双引号内的反斜杠。
$ grep '\(then\|there\)' x.x
在这种情况下,分组是不必要的。
$ grep 'then\|there' x.x
对于这样的事情是必要的:
$ grep 'the\(n\|re\)' x.x
答案2
只是一个快速的补充,大多数风格都有一个名为egrep的命令,它只是带有-E的grep。我个人更喜欢打字
egrep "i(Pod|Pad|Phone)" access.log
比使用 grep -E
答案3
(或者至少是我的)手册页中正则表达式下记录的内容实际上是用于扩展正则表达式;
grep 理解正则表达式语法的三种不同版本:“基本”、“扩展”和“perl”。在 GNU grep 中,基本语法和扩展语法之间的可用功能没有区别。在其他实现中,基本正则表达式的功能不太强大。 以下描述适用于扩展正则表达式;随后总结了基本正则表达式的差异。
但 grep 默认情况下不使用它们——您需要开关-E
:
grep "(then|there)" x.x
因为(再次来自手册页):
基本正则表达式与扩展正则表达式
在基本正则表达式中,元字符 ?、+、{、|、( 和 ) 失去了它们的特殊含义;而是使用反斜杠版本 \?、+、{、\|、( 和 )。
所以你还可以使用:
grep "then\|there" x.x
因为在这种情况下括号是多余的。
答案4
Bash 的优雅简洁似乎在它庞大的手册页中消失了。
除了上面的优秀解决方案之外,我想我应该尝试给你一份备忘单bash 如何解析和解释语句。然后,我将使用此路线图解析提问者提供的示例,以帮助您更好地理解为什么它们不能按预期工作。
注意:直接使用 Shell 脚本行。键入的输入行首先进行历史扩展。
每个 bash 行首先被标记化,或者换句话说,切成所谓的代币。 (标记化发生在所有其他扩展之前,包括大括号、波形符、参数、命令、算术、进程、分词和文件名扩展。)
这里的标记是指由以下特殊元字符之一分隔(定界)的输入行的一部分:
space, - White space...
tab,
newline,
‘<’, - Redirection & piping...
‘|’,
‘>’
‘&’, - And/Both < | > | >> .or. &<file descriptor>
‘;’, - Command termination
‘(’, - Subshell, closed by - ‘)’
Bash 使用许多其他特殊字符,但只有这 10 个产生初始标记。
然而,由于这些元字符有时也必须在令牌中使用,因此需要有一种方法来消除它们的特殊含义。这就是所谓的逃避。转义可以通过引用一个或多个字符的字符串(即'xx..'
, "xx.."
)或在单个字符前添加反斜杠(即\x
)来完成。 (它比这更复杂一点,因为引号也需要引用,而且双引号并不引用所有内容,但这种简化现在就可以了。)
不要将 bash 引用与引用文本字符串的想法混淆,就像在其他语言中一样。 bash 中引号之间的内容不是字符串,而是输入行中经过元字符转义的部分,因此它们不会分隔标记。
'
请注意, 、 和之间有一个重要的区别"
,但那是另一天的事了。
剩余的未转义元字符将成为标记分隔符。
例如,
$ echo "x"'y'\g
xyg
$ echo "<"'|'\>
<|>
$ echo x\; echo y
x; echo y
在第一个示例中,有两个由空格分隔符生成的标记:echo
和xyz
。
第二个例子也是如此。
在第三个示例中,分号被转义,因此空格分隔符 、 、 、 和 产生了echo
4x;
个echo
标记y
。然后第一个令牌作为命令运行,并接受接下来的三个令牌作为输入。请注意,第二个echo
未执行。
要记住的重要一点是,bash 首先查找转义字符('
、"
和\
),然后按顺序查找未转义的元字符分隔符。
如果未转义,则这 10 个特殊字符将用作token
分隔符。其中一些还具有其他含义,但首先也是最重要的是,它们是标记分隔符。
grep 期望什么
在上面的示例中,grep 需要这些标记,grep
, string
, filename
。
这个问题的第一次尝试是:
$ grep (然后|那里) xx
在本例中(
,)
、 和|
是未转义的元字符,因此用于将输入拆分为以下标记:grep
、(
、then
、|
、there
、)
和x.x
。 grep 想查看grep
、then|there
、 和x.x
。
问题的第二次尝试是:
grep "(然后|那里)" xx
这标记为grep
, (then|there)
, x.x
。如果将 grep 替换为 echo,您可以看到这一点:
echo "(然后|那里)" xx
(然后|那里) xx