使用 \\ 的正则表达式与使用 \ 的正则表达式

使用 \\ 的正则表达式与使用 \ 的正则表达式

为什么

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

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

做同样的事情?

如果我添加第三个斜杠,也会得到相同的结果。但是,一旦我添加第四个斜杠,它就不再起作用了。这与旧课程考试中的一个问题有关。它询问带有两个反斜杠的那个是否可以输出带有“eg”的行,我最初认为它不起作用,但我试图确保它确实起作用。解释是什么?

答案1

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

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

据,直到...为止重击就而言,转义期与句期相同。 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,在上面三个测试中的第一个测试中,如我们所愿,在句点之前看到一个单斜杠。因此,这是正确的做法。

通过三重斜线,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
\. \\. \\\. \\\\.

答案2

仅对于您的字符串,输出是相同的,但通常这些正则表达式会执行不同的操作。让我们稍微修改一下您的示例,添加第二个模式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.
    
  • 但我们可以\用另一个转义\,以便文字\将匹配后跟.(即任何字符):

    $ 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\.
    

现在,因为您没有使用''around 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

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

要查看 shell 如何查看您正在执行的操作,请使用 echo (例如echo grep e\\.g\\. <<< "this is an e.g. wow"vs. echo grep e\\\\.g\\\\. <<< "this is an e.g. wow"

答案4

这两个命令仅针对您的输入产生相同的输出,但在其他方面它们是不同的。为了理解发生了什么,我们必须先知道参数是如何解释的,bash然后是如何解释的grep

在 bash 中转义

\是一个特殊字符,它取消了后续字符(包括\其本身)的特殊含义。如果后面的字符没有特殊含义,则不加更改地传递。带有命令和结果的示例:

  • echo \a: a— 转义的普通字符给出了该字符
  • echo \\: \— 特殊字符转义给出了该字符
  • echo \\\a\a——组合特殊、普通
  • echo \\\\: \\— 组合特殊、特殊

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

.中没有特殊含义bash。它是 shell 的一个普通字符。以下是与您的示例相关的序列:

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

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

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

grep 中的正则表达式

\是一个转义字符,其含义与 中类似bash.是一个特殊字符代表任何字符的一次出现。看:POSIX 正则表达式,GNU grep 正则表达式。正则表达式示例:

  • .— 匹配任何字符,例如aor.
  • \.— 仅.字面匹配

你的例子

在下面每个示例的第二行,您将找到带有单引号的等效项,'显示哪个文字字符串传递bashgrep。然后,在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.

相关内容