Mar*_*tin 4 grep regular-expression
为什么不能grep -E
像我期望的那样对负空格起作用?IE[^\s]+
我写了一个正则表达式来解析我的 .ssh/config
grep -Ei '^host\s+[^*\s]+\s*$' ~/.ssh/config
# cat ~/.ssh/config
Host opengrok-01-Eight
Hostname opengrok-01.company.com
Host opengrok-02-SIX
Hostname opengrok-02.company.com
Host opengrok-03-forMe
Hostname opengrok-03.company.com
Host opengrok-04-ForSam
Hostname opengrok-04.company.com
Host opengrok-05-Okay
Hostname opengrok-05.company.com
Host opengrok-05-Okay opengrok-03-forMe
IdentityFile /path/to/file
Host opengrok-*
User root
Run Code Online (Sandbox Code Playgroud)
我得到的是
Host opengrok-01-Eight
Host opengrok-03-forMe
Host opengrok-05-Okay
Host opengrok-05-Okay opengrok-03-forMe
Run Code Online (Sandbox Code Playgroud)
六和山姆在哪里!
我花了一些时间才意识到[^\s*]+
ie 匹配任何不是空白或*
, 1 次或多次实际上是匹配任何不是\
,s
或*
1 次或多次!
修复非常简单,因为该正则表达式适用于 rex101.com(使用 perl),即切换-E
为-P
# grep -Pi '^host\s+[^*\s]+\s*$' ~/.ssh/config
Host opengrok-01-Eight
Host opengrok-02-SIX
Host opengrok-03-forMe
Host opengrok-04-ForSam
Host opengrok-05-Okay
Run Code Online (Sandbox Code Playgroud)
令我害怕的是我多年来一直grep -E
在许多脚本中使用,但以前没有发现过。也许我只是很幸运,但更有可能的是我的测试用例错过了那个边缘案例!
问题:
grep -P
用于我所有的扩展正则表达式之外,我应该如何grep -E
为这种情况编写我的?-E
或者如果我使用它会咬我-P
?grep (GNU grep) 3.1
Copyright (C) 2017 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>.
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.
Written by Mike Haertel and others, see <http://git.sv.gnu.org/cgit/grep.git/tree/AUTHORS>.
Run Code Online (Sandbox Code Playgroud)
在 Windows 10 上运行,WSL 运行 Ubuntu 18.04 (bash) ...但我从正确的 Linux 安装中得到了相同的结果
tha*_*isp 11
\s
is的补码\S
, not [^\s]
which(在 的帮助下-i
)从结果中排除了 'SIX' 和 'Sam',因为它们包含文字s
.
如何grep -i
为以“host”开头的行,后跟一个或多个空格和一个或多个字符的序列,直到行尾,其中不*
存在文字或空格:
grep -Ei '^host[[:space:]]+[^*[:space:]]+$' file
Run Code Online (Sandbox Code Playgroud)
Host opengrok-01-Eight
Host opengrok-02-SIX
Host opengrok-03-forMe
Host opengrok-04-ForSam
Host opengrok-05-Okay
Run Code Online (Sandbox Code Playgroud)
解释\s
为空格是 GNU Grep 的扩展。它没有在POSIX 中定义。例如,BSD Grep不会识别\s
为空格。Perl 正则表达式也是 POSIX 的扩展,但 BSD 和 GNU 都提供了它。对于完全可移植的表达式,您应该[[:space:]]
改用。
GNU Grep 手册有些松散地说明“大多数元字符在括号表达式中失去了它们的特殊含义”。你已经发现\s
是其中之一,它是由指定的其实POSIX(再次)的特殊字符.
,*
,[
并\
应在括号表达式中失去它们的特殊含义。但是您仍然可以便携地使用[:space:]
.
所以,回答你的两个问题,
我应该如何
grep -E
为这个案例写我的?
grep -Ei '^host[[:space:]]+[^*[:space:]]+[[:space:]]*$'
Run Code Online (Sandbox Code Playgroud)
是否有任何其他令人讨厌的问题是我一直遗漏的,
-E
或者如果我使用它会咬我-P
?
一个常见的错误是在.*?
没有-P
标志的情况下尝试 Perl 非贪婪。
$ echo 'AB 14 34' | grep -Eo '^.*?4'
AB 14 34
$ echo 'AB 14 34' | grep -Po '^.*?4'
AB 14
$ echo 'AB 14 34' | grep -o '^.*?4'
{nothing}
Run Code Online (Sandbox Code Playgroud)
最后一句话:BRE 和 ERE和 PRE 都是不同的。了解您的正则表达式!