首页 > 解决方案 > bash 中 grep 对前面有几个相同字符的行的意外行为

问题描述

我正在玩overthewire.org强盗达到 10 级需要我在文本文件中查找前面有几个“=”字符(等号)(我将“几个”解释为“两个或更多”)的字符串。

目标行如下所示:

========== passwordhere123

即十个等号、一个空格和一串字母和数字,然后是换行符(不确定是哪种确切类型)。

应排除这些行:

c========== EqualSignDidNotStartLine

= only-one-equal-sign

equalsign=somewhereElse

No equal signs at all

原始数据不包含任何前面有少于十但多于一个 = 的行;文本中有一些 +(加号),但 + 和 = 永远不会在同一行。

强盗服务器运行某种 linux @ 4.18.12 (uname -r)、GNU bash 4.4(来自手册页)和 GNU grep 2.27(来自手册页)。

原始数据包含不可读的部分,因此它首先被输入strings,只留下人类可读的字符串来处理 grep。

据我所知,grep 的默认正则表达式引擎(BRE,感谢Casimir)与 PCRE 的区别不大。*仍然是一个量词(匹配前面的模式零次或多次),而不是作为一个独立的模式,意思是“任何东西,零次或多次”。这让我对下面 grep 的行为感到困惑。

编辑:根据此图表,“+”需要\+在 BRE 中转义(即)。但它无济于事。我将制作更多的测试字符串来尝试破译发生了什么。

这是我尝试过的命令:

strings data.txt | grep -P -e ^==+.*

strings data.txt | grep -P -e ^==+.*$ #both PCRE expressions worked correctly

#start BRE

strings data.txt | grep -e ^==.*    #includes every line preceded by at least two =; works

strings data.txt | grep -e ^==.*$   #includes every line preceded by at least two =; works

strings data.txt | grep -e ^==+.*   #no output; why?

strings data.txt | grep -e ^==+.*$  #no output

strings data.txt | grep -e ^==+*    #includes every target line, so works; WHY IS THIS A LEGAL REGEX?

strings data.txt | grep -e ^==+*$   #no output

strings data.txt | grep -e ^==\+.*  #no output

strings data.txt | grep -e ^==\+.*$ #no output

strings data.txt | grep -e ^==\+*   #includes every target line, so works

strings data.txt | grep -e ^==\+*$  #no output

标签: regexbashgrep

解决方案


首先,我会担心外壳扩展。根据长期经验,我将正则表达式放在命令行中的“单引号”中,以避免元字符的疯狂。

其次,这个(在BRE下):

^==+*

是完全有效的。它的意思是:

^     anchored at the start of the input
==    followed by 2 '=' charaters
+*    followed by 0 or more '+' characters 

您说“根据我所学到的,grep 的默认正则表达式引擎(BRE,感谢 Casimir)与 PCRE 应该没有太大不同”,我认为这是您的问题。特别是,+是PRCE 中的元字符,而不是BRE 中的元字符。观察:

echo '==+++++' | grep ^==+*
==+++++

echo '==+++++' | grep -E ^==+*
grep: repetition-operator operand invalid

-Eongrep启用扩展的正则表达式。

那么,既然您知道这+只是+BRE 下的文字,您能明白为什么所有模式的行为方式都如此吗?


推荐阅读