grep
无法输入“原始”字符串,因为某些字符需要转义才能被视为文字。例如:
$ grep '(hello|bye)' # WON'T MATCH 'hello'
$ grep '\(hello\|bye\)' # GOOD, BUT QUICKLY BECOMES UNREADABLE
我使用printf
自动转义字符串:
$ printf '%q' '(some|group)\n'
\(some\|group\)\\n
这会生成字符串的bash-escaped版本,并且使用反引号,可以很容易地将其传递给grep调用:
$ grep `printf '%q' '(a|b|c)'`
但是,它显然不适用于此:输出中的某些字符不会被转义,而有些则不必要。例如:
$ printf '%q' '(^#)'
\(\^#\)
传递给^
时,grep
字符不应转义。
是否有一个cli工具接受原始字符串并返回字符串的bash-escaped版本,可以直接用作grep 的模式?如果没有,我怎么能用纯粹的bash来实现呢?
答案 0 :(得分:40)
如果您想搜索确切的字符串,
grep -F '(some|group)\n' ...
-F
告诉grep
按原样处理模式,没有解释为正则表达式。
(这通常也以fgrep
的形式提供。)
答案 1 :(得分:21)
如果您试图让grep
使用扩展正则表达式语法,那么执行此操作的方法是使用grep -E
(又名egrep
)。您还应该了解grep -F
(又名fgrep
)以及更新版本的GNU Coreutils grep -P
。
背景:原始grep
有一组相当少的正则表达式运算符;这是Ken Thompson最初的正则表达式实现。后来开发了具有扩展曲目的新版本,并且出于兼容性原因,获得了不同的名称。使用GNU grep
时,只有一个二进制文件,如果调用grep
,则理解传统的基本RE语法,如果调用egrep
,则理解ERE。 egrep
中的一些构造在grep
中可用,通过使用反斜杠转义来引入特殊含义。
随后,Perl编程语言进一步扩展了形式主义;这种正则表达方言似乎是大多数新人错误地期望grep
支持的。使用grep -P
,确实如此;但目前尚未在所有平台上广泛支持。
因此,在grep
中,以下字符具有特殊含义:^$[]*.\
在egrep
中,以下字符也具有特殊含义:()|+?{}
。 (重复的大括号不在原始egrep
中。)分组括号还支持使用\1
,\2
等进行反向引用。
在grep
的许多版本中,您可以通过在egrep
特价之前加一个反斜杠来获得egrep
行为。还有一些特殊的序列,如\<\>
。
在Perl中,引入了大量额外的转义,例如\w
\s
\d
。在Perl 5中,正则表达式工具大幅扩展,非贪婪匹配*?
+?
等,非分组括号(?:...)
,前瞻,后观等。
...话虽如此,如果您确实想要将egrep
正则表达式转换为grep
正则表达式而不调用任何外部进程,请尝试{{1} }对于每个${regex/pattern/substitution}
特殊字符;但要认识到这不能正确处理字符类,否定字符类或反斜杠转义。
答案 2 :(得分:19)
当我使用grep -E和用户提供的字符串时,我用这个
来逃避它们ere_quote() {
sed 's/[]\.|$(){}?+*^]/\\&/g' <<< "$*"
}
示例运行
ere_quote ' \ $ [ ] ( ) { } | ^ . ? + *'
# output
# \\ \$ \[ \] \( \) \{ \} \| \^ \. \? \+ \*
这样您就可以安全地在正则表达式中插入带引号的字符串。
e.g。如果你想找到以用户内容开头的每一行,用户提供有趣的字符串为。*
userdata=".*"
grep -E -- "^$(ere_quote "$userdata")" <<< ".*hello"
# if you have colors in grep you'll see only ".*" in red
答案 3 :(得分:3)
我认为之前的答案并不完整,因为他们错过了一件重要的事情,即以破折号( - )开头的字符串。所以,虽然不会工作:
echo "A-B-C" | grep -F "-B-"
这个会:
echo "A-B-C" | grep -F -- "-B-"
答案 4 :(得分:0)
下面仅需说明示例,该示例显示grep将子字符串“ -B”解释为命令行选项,并且命令失败。
echo "A-B-C" | grep -F "-B-"
grep 在这种情况下有一个特殊的选择:
-e模式,-regexp =模式 使用模式作为模式。如果此选项多次使用或与-f(--file)选项结合使用, 搜索所有给定的模式。此选项可用于保护以“-”开头的模式。
因此,此问题的解决方法是:
echo "A-B-C" | grep -F -e "-B-" -
答案 5 :(得分:0)
quote() {
sed 's/[^\^]/[&]/g;s/[\^]/\\&/g' <<< "$*"
}
用法:grep [OPTIONS] "$(quote [STRING])"
此功能有很多实质性的好处:
quote
独立于正则表达式。您可以在以下位置使用quote
的输出
grep
(-G
)`(默认为BRE)grep -E
(ERE)grep -P
(PCRE)sed
(-E
) "s/$(quote [STRING])/.../"
(只要您不使用\
,[
或]
而不是{ {1}}。/
甚至在不直接引用的极端情况下工作
-
,以便不会被quote
误解为选项。grep
删除。 $(...)
仅在quote
包含换行符时失败。但总的来说,这没有解决办法,因为[STRING]
和grep
之类的工具可能不支持其搜索模式中的换行符(即使它们写为sed
)。
还有一个缺点,就是报价输出通常比未报价输入长三倍。