如何在文件中 grep 查找这个或那个(2 件事)?

如何在文件中 grep 查找这个或那个(2 件事)?

我有一个包含“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

在第一个示例中,有两个由空格分隔符生成的标记:echoxyz

第二个例子也是如此。

在第三个示例中,分号被转义,因此空格分隔符 、 、 、 和 产生了echo4x;echo标记y。然后第一个令牌作为命令运行,并接受接下来的三个令牌作为输入。请注意,第二个echo未执行。


要记住的重要一点是,bash 首先查找转义字符('"\),然后按顺序查找未转义的元字符分隔符。

如果未转义,则这 10 个特殊字符将用作token分隔符。其中一些还具有其他含义,但首先也是最重要的是,它们是标记分隔符。


grep 期望什么

在上面的示例中,grep 需要这些标记,grep, string, filename

这个问题的第一次尝试是:

$ grep (然后|那里) xx

在本例中()、 和|是未转义的元字符,因此用于将输入拆分为以下标记:grep(then|there)x.x。 grep 想查看grepthen|there、 和x.x

问题的第二次尝试是:

grep "(然后|那里)" xx

这标记为grep, (then|there), x.x。如果将 grep 替换为 echo,您可以看到这一点:

echo "(然后|那里)" xx
(然后|那里) xx

相关内容