正则表达式使用\\与\


10

为什么

grep e\\.g\\. <<< "this is an e.g. wow"

grep e\.g\. <<< "this is an e.g. wow"

做同样的事情?

如果添加第三个斜杠,则结果也相同。但是,一旦我添加了第四个斜杠,它将不再起作用。这与旧的考试题有关。它询问带有两个反斜杠的那个是否可以输出带有“ eg”的行,我本来以为这行不行,但是我尝试确定并且确实如此。有什么解释?


我以为bash会接受\\\.grep并给予\.它,但事实并非如此。好问题

Answers:


9

首先,请注意,单个斜杠匹配太多:

$ echo $'eegg \n e.g.' | grep e\.g\.
eegg
 e.g.

Bash而言,转义时间与转义时间相同。Bash将这段时间传递给grep。对于grep,句点匹配任何内容。

现在,考虑:

$ echo $'eegg \n e.g.' | grep e\\.g\\.
 e.g.
$ echo $'eegg \n e.g.' | grep e\\\.g\\\.
 e.g.
$ echo $'eegg \n e.g.' | grep e\\\\.g\\\\.
$

当Bash看到一个双斜杠时,将其减为一个斜杠并将其传递给grep,在上面的三个测试中的第一个测试中,grep根据需要在一个句点之前看到一个单斜杠。因此,这做对了。

使用三斜杠,Bash将前两个斜杠减少为一个斜杠。然后看到\.。由于转义期对Bash没有特殊意义,因此可以将其缩短为简单期。结果是,grep在我们想要的时候在句号之前看到了一个斜线。

通过四个斜杠,Bash将每对减为一个斜杠。Bash传递给grep两个斜杠和一个句点。grep看到两个斜杠和一个句点,并将两个斜杠减少为单个文字斜杠。除非输入的文字斜杠后跟任何字符,否则没有匹配项。

为了说明最后一点,请记住在单引号内所有字符都是文字。因此,给定以下三行输入,grep命令仅在输入中带有文字斜杠的行上匹配:

$ echo 'eegg
e.g.
e\.g\.' |  grep e\\\\.g\\\\.
e\.g\.

Bash行为摘要

对于Bash,规则是

  • 两个斜杠减少为一个斜杠。

  • 普通字符前面的斜线(例如句点)只是普通字符(句号)。

从而:

$ echo \. \\. \\\. \\\\.
. \. \. \\.

有一种避免所有这些混乱的简单方法:在Bash命令行上,正则表达式应放在单引号中。在单引号内,Bash保留所有内容。

$ echo '\. \\. \\\. \\\\.'  # Note single-quotes
\. \\. \\\. \\\\.

问题:bash将其视为反斜杠需要两个反斜杠(一个是转义序列,另一个是文字反斜杠)。那么,当bash等于3时,是否也将第三个散乱者当作逃逸序列?由于它没有逃逸,因此是否将其丢弃?
Franz Kafka

@DanielAmaya第三个被视为后面角色的转义符。在我们的案例中,该字符是句点,对于bash(与grep不同),转义字符只是一个简单的句点。bash然后将简单的时期传递给grep。
John1024

@DanielAmaya请参阅更新的答案,以获取echo说明在这些情况下bash的功能的声明。
2014年

2
@DanielAmaya在这两种情况下,bash都会将前两个斜杠减少为一个斜杠。剩下的就是\..。对于bash来说,两者是相同的:它们相当于一个普通的时期。因此,总的来说,bash传递给grep的两者是相同的:单斜杠后跟一个句点。
2014年

1
只是一小部分- echo由于该程序的许多实现,因此使用不是测试regexp的可靠方法。例如在我的zsh(内置echo)下echo \. \\. \\\. \\\\. \\\\\.给出. \. \. \. \.,但/bin/echo \. \\. \\\. \\\\. \\\\\.返回. \. \. \\. \\.。喜欢的东西printf "%s" ...可能是更好的办法。
jimmij 2014年

4

输出仅对于您的字符串是相同的,但是通常那些正则表达式执行不同的操作。让我们通过添加第二个图案e,g,(带逗号),第三个e\.g\.(点),第四个e\,g\,(逗号)和-ogrep选项(仅打印匹配的部分)来对示例进行一些修改。

  • 在以下情况下.(通知匹配任何字符''左右e.g.,以后我会走到那)

    $ grep -o 'e.g.' <<< grep -o 'e.g.' <<< 'this is an e.g. e,g, e\.g\. e\,g\,'
    e.g.
    e,g,
  • 接下来,我们.使用反斜杠进行转义\,因此.将仅匹配文字:

    $ grep -o 'e\.g\.' <<< 'this is an e.g. e,g, e\.g\. e\,g\,'
    e.g.
  • 但是我们可以\使用another 来转义\,这样文字\将匹配后跟.(即任何char):

    $ grep -o 'e\\.g\\.' <<< 'this is an e.g. e,g, e\.g\. e\,g\,'
    e\.g\.
    e\,g\,
  • 但是,如果我们想只匹配\.\,那么又\需要逃脱点的特殊含义:

    $ grep -o 'e\\\.g\\\.' <<< 'this is an e.g. e,g, e\.g\. e\,g\,'
    e\.g\.

现在,因为您没有''在grep参数周围使用,所以您需要添加另一个反斜杠来避免反斜杠从shell解释中退出,因此:

grep 'e\.g\.'     => grep e\\.g\\.
grep 'e\\.g\\.'   => grep e\\\\.g\\\\.  (each backslash has to be quoted separately)
grep 'e\\\.g\\\.' => grep e\\\\\\.g\\\\\\. (3 x 2 = 6 backslashes in total)

3

当您执行时grep e\.g\.,shell会消耗反斜杠,因此您正在执行grep e.g.,该匹配。当您执行时grep e\\.g\\.,shell再次使用斜杠,而现在您正在执行grep e\.\g.,再次匹配。现在,外壳的反斜杠看起来像\\。因此,当具有时\\,第一个是转义序列,第二个是文字反斜杠。当您执行a时grep e\\\.g\\\.,它仍然最终会存在grep e\.\g.,因为\在第一个\将其变为文字之前没有转义序列()\。请记住\是一个反斜杠,因此grep e\\\\.\\\\g最终成为grep e\\.g\\.,显然不匹配。

要查看外壳如何查看您在做什么,请使用echo(例如echo grep e\\.g\\. <<< "this is an e.g. wow"vs echo grep e\\\\.g\\\\. <<< "this is an e.g. wow")。


0

这两个命令只为您的输入产生相同的输出,否则它们是不同的。对于什么是对我们怎么理解必须知道如何为参数首先解释bash,然后通过grep

逃避重击

\是一个特殊字符,它取消了后续字符(包括\其自身)的特殊含义。如果以下字符没有特殊含义,则将其原封不动地传递。命令和结果示例:

  • echo \aa-普通字符转义给出字符
  • echo \\\—转义的特殊字符赋予该字符
  • echo \\\a\a—特殊组合,普通
  • echo \\\\\\—特殊组合,特殊

echobash解释后将打印结果字符串。更多信息:bash文档bash黑客WikiPOSIX规范

.在中没有特殊含义bash。这是外壳的普通字符。以下是与您的示例相关的序列:

  • echo ..
  • echo \..
  • echo \\.\.
  • echo \\\.\.
  • echo \\\\.\\.

bash中文字字符串的更简单解决方案

要从字面上传递参数,bash可以使用单引号'转义。在单引号之间,您不必关心字符的特殊含义,因为单引号是唯一具有特殊含义的字符。您可以在将字符串的第一部分括起来之后插入单引号。例如
echo 'part1'\''part2'part1'part2

grep中的正则表达式

\是转义字符,含义与中的相似bash.是一个特殊字符,表示任何字符的一次出现。请参阅:POSIX regexGNU grep regex。正则表达式的示例:

  • .—匹配任何字符,例如a.
  • \.—仅从.字面上匹配

你的例子

在下面每个示例的第二行,您都将找到等效的单引号',该单引号显示了传递bash给的文字字符串grep。然后,在grep执行转义后,示例中唯一可能的特殊字符.与任何字符都匹配。第三行上有一个表达式匹配的描述。

  • grep e.g. <<< "this is an e.g. wow"
    grep 'e.g.' <<< "this is an e.g. wow"
    e任何字符g任何字符 - 匹配e.g.,可能还包含其他字符串,例如eagb
  • grep e\.g\. <<< "this is an e.g. wow"
    grep 'e.g.' <<< "this is an e.g. wow"
    e任何字符g任何字符 - 匹配e.g.,可能还包含其他字符串,例如exgy
  • grep e\\.g\\. <<< "this is an e.g. wow"
    grep 'e\.g\.' <<< "this is an e.g. wow"
    e.g.从字面上看- 匹配e.g.
  • grep e\\\.g\\\. <<< "this is an e.g. wow"
    grep 'e\.g\.' <<< "this is an e.g. wow"
    e.g.从字面上看- 匹配e.g.
  • grep e\\\\.g\\\\. <<< "this is an e.g. wow"
    grep 'e\\.g\\.' <<< "this is an e.g. wow"
    e\任何字符g\任何字符 - 不匹配e.g.
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.