在命令行上转义正则表达式反斜杠所需的反斜杠数

dan*_*ann 13 command-line shell quoting regular-expression

我最近在命令行上遇到了一些正则表达式的问题,发现为了匹配反斜杠,可以使用不同数量的字符。这个数字取决于用于正则表达式的引用(无、单引号、双引号)。请参阅以下 bash 会话以了解我的意思:

echo "#ab\\cd" > file
grep -E ab\cd file
grep -E ab\\cd file
grep -E ab\\\cd file
grep -E ab\\\\cd file
#ab\cd
grep -E ab\\\\\cd file
#ab\cd
grep -E ab\\\\\\cd file
#ab\cd
grep -E ab\\\\\\\cd file
#ab\cd
grep -E ab\\\\\\\\cd file
grep -E "ab\cd" file
grep -E "ab\\cd" file
grep -E "ab\\\cd" file
#ab\cd
grep -E "ab\\\\cd" file
#ab\cd
grep -E "ab\\\\\cd" file
#ab\cd
grep -E "ab\\\\\\cd" file
#ab\cd
grep -E "ab\\\\\\\cd" file
grep -E 'ab\cd' file
grep -E 'ab\\cd' file
#ab\cd
grep -E 'ab\\\cd' file
#ab\cd
grep -E 'ab\\\\cd' file
Run Code Online (Sandbox Code Playgroud)

这意味着:

  • 没有引号,我可以将反斜杠与 4-7 个实际反斜杠匹配
  • 使用双引号,我可以将反斜杠与 3-6 个实际反斜杠匹配
  • 使用单引号,我可以将反斜杠与 2-3 个实际反斜杠匹配

我知道 shell 会忽略一个额外的反斜杠(来自 bash 手册页):

“一个不带引号的反斜杠 (\) 是转义字符。它保留了下一个字符的字面值”

这不适用于单引号示例,因为单引号中没有进行转义。

并且 grep 命令忽略了一个额外的反斜杠(“\c”只是“c”转义,但这与“c”相同,因为“c”在正则表达式中没有特殊含义)。

这用单引号解释了示例的行为,但我不太了解其他两个示例,尤其是为什么非引用字符串和双引号字符串之间存在差异。

再次引用来自 bash 手册页的引用:

“用双引号括起来的字符会保留引号内所有字符的字面值,除了 $、`、\,并且在启用历史扩展时,!。”

我对 GNU awk(例如awk /ab\cd/{print} file)进行了同样的尝试,结果相同。

然而,Perl 显示不同的结果(使用 eg perl -ne "/ab\\cd/"\&\&print file):

  • 没有引号,我可以将反斜杠与 4-5 个实际反斜杠匹配
  • 使用双引号,我可以将反斜杠与 3-4 个实际反斜杠匹配
  • 使用单引号,我可以将反斜杠与 2 个实际的反斜杠匹配

任何人都可以解释 grep 和 awk 命令行上非引号和双引号正则表达式字符串之间的区别吗?我对解释 Perl 的行为并不感兴趣,因为我通常不使用 Perl 单行程序。

Ans*_*ann 11

对于未加引号的示例,每一\\对都将一个反斜杠传递给 grep,因此 4 个反斜杠将两个反斜杠传递给 grep,从而转化为单个反斜杠。6 个反斜杠将三个传递给 grep,转换为一个反斜杠和一个\c,等于c. 一个额外的反斜杠不会改变任何东西,因为它是由 shell翻译\c->c的。shell 中的八个反斜杠在 grep 中是四个,转换为两个,因此不再匹配。

对于双引号中的示例,请注意 bash 手册页中第二个引号后面的内容:

反斜杠仅在后跟以下字符之一时保留其特殊含义:$、`、"、\ 或换行符。

即,当您给出奇数个反斜杠时,序列以 结尾\c,这c在不带引号的情况下等于,但是当引用时,反斜杠失去了它的特殊含义,因此\c传递给 grep。这就是为什么“可能的”反斜杠范围(即那些构成与示例文件匹配的模式的)向下滑动一个的原因。


Pet*_*r.O 6

此链接描述了 bash引号和转义

您的问题涉及前三个部分。

  • 每个字符转义
  • 弱引用 “双引号”
  • 强引用 '单引号'
  • ANSI C 喜欢字符串引用
  • I18N/L10N 引用(国际化和本地化)

下面是字符串如何bash传递给它们grep以及如何在grep内部进一步解释它们的图表。

我们先来看看echo "#ab\\cd" > file
弱引用("") 中"#ab\\cd", the \\是一个转义的\,它file作为单个文字传递给\。所以,file包含 ab\cd

现在,对于您的命令:下表可能有助于了解每次调用的实际情况。该*显示匹配文件内容的人。这实际上只是应用 bash 的转义规则的问题,就像在网页上一样,特别要注意daniel kullmann 的回答,他指的是在弱引用情况下的转义行为。

反斜杠仅在后跟以下字符之一时保留其特殊含义:$、`、"、\ 或换行符。


                            bash passes    grep further
                            to grep        resolves to         
grep -E ab\cd file            abcd           abcd   
grep -E ab\\cd file           ab\cd          abcd  
grep -E ab\\\cd file          ab\cd          abcd
grep -E ab\\\\cd file         ab\\cd         ab\cd    * 
grep -E ab\\\\\cd file        ab\\\cd        ab\cd    *
grep -E ab\\\\\\cd file       ab\\\cd        ab\cd    *    
grep -E ab\\\\\\\cd file      ab\\\cd        ab\cd    *
grep -E ab\\\\\\\\cd file     ab\\\\cd       ab\\cd

grep -E "ab\cd" file          ab\cd          abcd
grep -E "ab\\cd" file         ab\cd          abcd
grep -E "ab\\\cd" file        ab\\cd         ab\cd    *
grep -E "ab\\\\cd" file       ab\\cd         ab\cd    *
grep -E "ab\\\\\cd" file      ab\\\cd        ab\cd    *
grep -E "ab\\\\\\cd" file     ab\\\cd        ab\cd    *
grep -E "ab\\\\\\\cd" file    ab\\\\cd       ab\\cd    

grep -E 'ab\cd' file          ab\cd          abcd  
grep -E 'ab\\cd' file         ab\\cd         ab\cd    *
grep -E 'ab\\\cd' file        ab\\\cd        ab\cd    *
grep -E 'ab\\\\cd' file       ab\\\\cd       ab\\cd
Run Code Online (Sandbox Code Playgroud)