為什麼我的 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 使用轉義序列。

相關內容