为什么我的 grep 表达式需要使用 $'string' 来匹配制表符?

为什么我的 grep 表达式需要使用 $'string' 来匹配制表符?

如果你使用这段代码:

echo -e '\t\t\tString' | grep '^[\t]*String'

结果是空白的,因为它不匹配,但是:

echo -e '\t\t\tString' | grep $'^[\t]*String'

作品。我发誓我一定在我的脚本和终端中使用了第一行代码一百次,而从未使用过这样的“$”字符,而且它似乎总是有效。最近有什么变化吗?为什么需要“$”字符?或者我做错了什么?

答案1

ANSI-C 引用

根据 Bash 手册,这称为ANSI-C 引用。手册说:

形式的词$'字符串'受到特殊对待。该单词扩展为字符串,并按照 ANSI C 标准指定的方式替换反斜杠转义字符。

实际上,这意味着'\t'不会扩展为制表符,但$'\t'会扩展。输出应该等同于 using echo -e,但可以在任何使用字符串的地方使用,而不需要命令替换

像 GNU sed 这样的实用程序会执行自己的转义字符扩展,但 GNU grep 不会。 Bash shell(而不是 grep)会扩展 ANSI-C 带引号的字符串中的转义字符。如果没有 ANSI-C 引用,您发布的正则表达式将不包含与输入匹配的制表符。

答案2

您可能应该意识到不存在单一类型的正则表达式。至少有basic regular expressionsBRE(有时只有RE)、extended regular expressionsEREperl compatible regular expressionsPCRE。所有这些语言使用的语法都略有不同。当前版本GNU grep支持所有三个并且BRE是默认的。因为ERE您需要使用-Eoption 和 for PCRE -Poption。您的示例仅适用-P于基本和扩展 RE,反斜杠失去其含义并[\t]匹配反斜杠或字符 t。您可能在PCRE默认支持的其他语言中使用该模式,这是有道理的,因为它们是最强大的版本。或者也许你在alias grep='grep -P'某个地方。

答案3

如果省略 . 则第一行有效^。也许它有效,但没有按照您想象的方式工作?我怀疑grep其行为在如此重要的一点上发生了变化。

echo默认情况下不翻译转义序列。你需要-e为此。与外壳类似。您需要$'...'使 shell 使用转义序列。

相关内容