为什么 egrep 忽略负空格?

为什么 egrep 忽略负空格?

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

我得到的是

Host opengrok-01-Eight
Host opengrok-03-forMe
Host opengrok-05-Okay
Host opengrok-05-Okay opengrok-03-forMe

六号和山姆在哪里!

我花了一些时间才意识到[^\s*]+ie 匹配任何不是空格或*, 1 次或多次的内容实际上是匹配任何不是\, s, *, 1 次或多次的内容!

修复非常简单,因为正则表达式适用于 rex101.com(使用 perl),即-Eswitch-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

让我害怕的是我多年来一直grep -E在许多脚本中使用,但之前没有发现这一点。也许我只是运气好,但更可能的是我的测试用例错过了那个边缘情况!

问题:

  1. 除了更改为用于grep -P所有扩展正则表达式之外,我应该如何grep -E为这种情况编写我的正则表达式?
  2. 是否还有其他我遗漏的令人讨厌的问题-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>.

在 Windows 10 上运行,WSL 运行 Ubuntu 18.04 (bash) ...但我从正确的 Linux 安装中得到了相同的结果

答案1

的补码\s\S, not [^\s]which (在 的帮助下-i)将 'SIX' 和 'Sam' 从结果中排除,因为它们包含文字s


如何grep -i处理以“host”开头,后跟一个或多个空格以及一系列一个或多个字符直到行尾,其中不能*存在文字或空格:

grep -Ei '^host[[:space:]]+[^*[:space:]]+$' file
Host opengrok-01-Eight
Host opengrok-02-SIX
Host opengrok-03-forMe
Host opengrok-04-ForSam
Host opengrok-05-Okay

答案2

解释\s为空白是 GNU Grep 的扩展。它没有定义在POSIXBSD 查询例如,不识别\s为空格。 Perl 正则表达式也是 POSIX 的扩展,但 BSD 和 GNU 都提供它。对于完全可移植的表达式,您应该使用[[:space:]]

GNU Grep 手册有点松散地说“大多数元字符在括号表达式中失去了它们的特殊含义”。你已经发现这\s是其中之一,它实际上是由POSIX(再次)特殊字符.*[\在括号表达式中应该失去其特殊含义。但您仍然可以便携式使用[:space:]

那么,回答你的两个问题,

我应该如何grep -E为这个案例写我的文章?

grep -Ei '^host[[:space:]]+[^*[:space:]]+[[:space:]]*$'

是否还有其他我遗漏的令人讨厌的问题-E或者如果我使用的话会咬我的问题-P

.*?一个常见的错误是在没有标志的情况下尝试非贪婪的 Perl -P

$ 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}

最后一句话:BRE 和 ERE和 PRE 都是不同的。了解你的正则表达式!

相关内容