处理 grep 模式中空格的正确方法

处理 grep 模式中空格的正确方法

最新的grep 3.8对用反斜杠转义空格的模式发出警告

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

而 grep 3.6 则不会抱怨。处理这种模式的正确方法是什么?就是不逃离空间? IE

$ grep "bla bazz" t

是否有一些更奇特的greps 会错误地处理未转义的空间?也许,使用不同的配额来使一切变得漂亮和干净?

答案1

空格字符在正则表达式中并不特殊(除了启用perl该标志时的 -like 表达式x),因此不得转义。\后跟空格会在 POSIX 正则表达式中产生未指定的结果。

所以你要:

grep 'blah bazz'

如果你想让它更明显,你可以使用:

grep 'blah[ ]bazz'

更一般地,您不应该将\is 放在不是正则表达式运算符的字符前面。其中X不是正则表达式运算符,\X很可能是,如果现在不是,也许在未来的版本中。例如,+, <,d不是基本的正则表达式运算符,但\<,\+\d用于某些grep实现。

您可能需要\在以下位置使用后跟空格:

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

foo barx标志打开时进行匹配。但即使这样,您还是希望这样做:

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 perlre有关perl 正则表达式和man pcrepatternPCRE(perl 兼容正则表达式)的详细信息,请参阅参考资料。使用\Q \E是另一种选择。

无论如何,虽然空格在 shell 语法中是特殊字符,但在正则表达式中不是,但有许多字符在两者中都是特殊字符,例如*, \, (, ), ?, , $, ^, [, ], 因此需要转义对于这两个 if 意味着按字面匹配,最好对 shell 加上引号,并用\(或[...],或者\Q...\E在类似 perl 的情况下)来表示正则表达式。

由于\$在正则表达式中很常见,并且这些字符对于双引号内的 shell 来说仍然是特殊的,因此将正则表达式放在单引号而不是双引号中是一个好习惯。仅当您需要将 shell 参数扩展到正则表达式中grep "^$var"或需要'在正则表达式中包含 a 时,才需要使用双引号。

grep正则表达式相反的文字字符串,或者换句话说,转义每一个正则表达式运算符,您可以使用-F(for Ffixed string) 选项grep。例如:

grep -F 'blah\ bazz'

将查找包含blah\ bazz.

答案2

你只需要转义一个空格来保护它免受 shell 的影响,而不是为了grep.空格字符对于正则表达式来说并不特殊,它们仅在 shell 中特殊,因为它们是 shell 用于定义参数的字符。因此,如果您的模式未加引号(这是一个坏主意),则您需要空间:

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

这确保了她的 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

但是,如果您引用您的模式,这将保护它免受 shell 的影响,并且不需要转义:

$ 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

答案3

从 3.8 发行说明开始(https://savannah.gnu.org/news/?id=10191):

带有杂散反斜杠的正则表达式现在会导致警告,因为
它们的未指定行为可能会导致意外结果。例如,'\a' 和 'a' 并不总是等价的
https://bugs.gnu.org/39678。同样,
以重复运算符开头的正则表达式或子表达式现在也会
由于其未指定的行为而导致警告;例如,*a(+b|{1}c)
现在有三个警告原因。这些警告旨在作为
过渡帮助;它们在未来的版本中可能会出现错误。

相关内容