Grep

處理 grep 模式中空格的正確方法

  • October 1, 2022

最新的grep 3.8對使用反斜杠轉義空格的模式發出警告

$ grep "bla\ bazz" t 
/tmp/bin/grep: warning: stray \ before white space
...

而 grep 3.6 沒有抱怨。處理這種模式的正確方法是什麼?只是不逃離空間?IE

$ grep "bla bazz" t

是否有一些更奇特grep的 ’s 會錯誤地處理未轉義的空間?也許,要使用不同的配額來使它變得乾淨整潔?

您只需要轉義一個空格以保護它免受外殼的影響,而不是grep. 空格字元對於正則表達式不是特殊的,它們僅在 shell 中是特殊的,因為它們是 shell 用來定義參數的。因此,如果您的模式未引用(這是一個壞主意),則需要空格:

$ echo 'foo bar' | grep -c foo\ bar
1

這確保 she shell 不會解析foo bar為兩個參數,將 .bar作為文件名傳遞給grep. 您可以通過以下方式看到這一點set -x

$ set -x
$ echo 'foo bar' | grep -c foo\ bar
+ grep -c 'foo bar'
+ echo 'foo bar'
1

如果你不逃跑,你會得到:

$ echo 'foo bar' | grep -c foo bar
+ grep -c foo bar
+ echo 'foo bar'
grep: bar: No such file or directory

但是,如果您引用您的模式,這將保護它免受外殼程序的影響,並且不需要轉義:

$ echo 'foo bar' | grep -c "foo bar"
+ grep --color -c 'foo bar'
+ echo 'foo bar'
1

或者

$ echo 'foo bar' | grep -c 'foo bar'
+ grep --color -c 'foo bar'
+ echo 'foo bar'
1

這就是為什麼grep現在當它在空格前看到文字(引用)\時會警告您:它警告您\ 只是變成(空格),因為沒有什麼可以逃脫,因此\沒有意義。當它不是“可轉義”時,它會對任何其他被轉義的字元執行相同的操作:

$ echo 'foo bar' | grep -c "f\oo\ bar"
+ grep --color -c 'f\oo\ bar'
+ echo 'foo bar'
grep: warning: stray \ before o
grep: warning: stray \ before white space
1

正則表達式中不特殊的空格字元(啟用標誌perl時的 -like除外x),因此不得轉義。\後跟空格會在 POSIX 正則表達式中產生未指定的結果。

所以你要:

grep 'blah bazz'

如果你想讓它更明顯,你可以使用:

grep 'blah[ ]bazz'

更一般地,您不應該將\is 放在不是正則表達式運算符的字元的前面。Where Xis not a 正則表達式運算符,\X很可能是,如果不是現在,也許在未來的版本中。例如,+, <,d不是基本的正則表達式操作符,但是\<,\+\d用於某些grep實現。

您可能希望在\後面使用空格:

grep -P '(?x)  foo \  bar'
perl -ne 'print if / foo \  bar /x'

在標誌打開foo bar時匹配。x但即使在那裡,你寧願這樣做:

grep -P '(?x)  foo [ ] bar'

使其更易讀。該x標誌的全部意義在於使正則表達式更清晰,例如:

perl -ne 'print if m{
 \d{4}   # year
 - \d{2} # month
 - \d{2} # day
 [ ] (foo | bar | baz)}x'

對比

perl -ne'print if/\d{4}-\d{2}-\d{2} (foo|bar|baz)/'

但是,您不能[ ]xx標誌一起使用(在 perl 5.26+ 中,而不是 PCRE),其中括號表達式中的空格也會被忽略。

有關perldoc perlreperl 正則表達式的詳細資訊,以及man pcrepatternPCRE(perl 兼容的正則表達式)的詳細資訊,請參閱。使用\Q \E是另一種選擇。

在任何情況下,雖然空格是 shell 語法中的特殊字元而不是正則表達式中的特殊字元,但有許多字元在兩者中都是特殊的,例如*, \, (, ), ?, $, ^, [, ], 所以需要轉義對於兩者,如果要按字面意思匹配,最好使用 shell 的引號,以及正則表達式的\(或[...],或\Q...\E類似 perl 的)。

由於\$在正則表達式中很常見,而且這些字元在雙引號內對 shell 來說仍然是特殊的,因此將正則表達式放在單引號而不是雙引號中是一個好習慣。如果您需要將 shell 參數擴展為正則表達式,grep "^$var"或者需要在正則表達式中包含 a ,則只能使用雙引號'

grep文字字元串而不是正則表達式,或者換句話說,要轉義每個正則表達式運算符,您可以使用-F(for Fixed string) 選項來grep. 例如:

grep -F 'blah\ bazz'

會尋找包含blah\ bazz.

引用自:https://unix.stackexchange.com/questions/719384