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

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

我最近在命令行上使用一些正则表达式时遇到了麻烦,发现为了匹配反斜杠,可以使用不同数量的字符。该数字取决于正则表达式使用的引号(无、单引号、双引号)。请参阅以下 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

这意味着:

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

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

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

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

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

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

再次引用 bash 手册页中的一段话:

“将字符括在双引号中会保留引号内所有字符的字面值,但 $、`、\ 和启用历史扩展时的 ! 除外。”

我尝试使用 GNU awk (例如) 进行相同操作awk /ab\cd/{print} file,结果相同。

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

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

谁能解释 grep 和 awk 命令行上非引号和双引号正则表达式字符串之间的区别?我对 Perl 行为的解释不太感兴趣,因为我通常不使用 Perl 的单行代码。

答案1

对于未加引号的示例,每一\\对将一个反斜杠传递给 grep,因此 4 个反斜杠将两个反斜杠传递给 grep,这会转换为单个反斜杠。 6 个反斜杠将 3 个传递给 grep,转换为 1 个反斜杠和 1 个\c,等于c。多一个反斜杠不会改变任何内容,因为它是由 shell翻译\c-> 的。 cshell 中的八个反斜杠在 grep 中是四个,转换为两个,所以这不再匹配。

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

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

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

答案2

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

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

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

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

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

现在,按照您的命令:下面的图表可能有助于了解每次调用的实际情况。显示与*文件内容匹配的内容。这实际上只是应用 bash 的转义规则的问题,就像在网页上一样,特别注意丹尼尔·库尔曼的回答他提到的逃避行为弱引用情况。

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


                            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

相关内容