Open Bpazy opened 2 years ago
在shell(以bash为例)中使用grep正则表达式时,一直以来一个严重困扰我的问题就是:grep正则的语法与“普通”编程语言(如Java,js,PHP等)里的不一样,简直太“文艺”了!比如{}, |, 等特殊符号,“普通”的正则是在它们之前加\表示转义(即不再具有特殊字符的作用,而作为普通字符匹配),但bash的grep却正好相反,;但”“却又相反,”\“表示匹配普通字符而”*“具有特殊含义。可以测试一下如下语句的输出:
> cat file.txt
aaa
a{3}
a*
aa
> grep "a{3}" file.txt
a{3}
>grep "a\{3\}" file.txt
aaa
>grep "^a*$" file.txt
aaa
aa
>grep "^a\*$" file.txt
a*
为什么grep摒弃代码世界里“反斜杠表示转义”的通用规则反其道而行之,简直百思不得其解。之前并未深究这个问题,得过且过,直到今天在刷leetcodeOJ时,看到新增的shell题型中有使用正则匹配的题目,自己在bash下老是试不出来,google一番后找到数篇科普文,终于茅塞顿开,现总结如下。
正则表达式的类型
常用shell命令的默认正则类型 | 命令 | 支持的正则类型 | 默认正则类型 | 使用其他正则类型的方法 |
---|---|---|---|---|
grep | BREs, EREs, PREs | BREs | -E表示使用EREs,-P表示使用PREs | |
egrep | EREs, PREs | EREs | -P表示使用PREs | |
pgrep | PREs | - | - | |
fgrep | 纯文本匹配,不支持正则 | - | - | |
sed | BREs | -r表示使用EREs | ||
awk | EREs | EREs | - |
grep/sed为BREs打的“补丁”
BREs缺少了EREs和PREs的很多特性,很多特殊字符也不支持,如|,{},()等。然而作为shell中最常用工具之一的grep和sed却不能无视这些缺陷,因此这些命令用一种独特的方式,给BREs原本不支持的特殊字符打上“补丁”:加反斜杠转义。之所以这么麻烦,是因为这些工具的诞生时间很早,正则表达式的许多功能却是逐步发展演化出来的。之前这些元字符可能并没有特殊的含义,为保证向后兼容,就只能使用转义。
引用自: grep使用中的怪象与正则表达式类型
所以结论:不要使用 grep -E
了,改为 grep -P
:
> $ grep --help
-E, --extended-regexp PATTERNS are extended regular expressions
-F, --fixed-strings PATTERNS are strings
-G, --basic-regexp PATTERNS are basic regular expressions
-P, --perl-regexp PATTERNS are Perl regular expressions
记录一些 grep 命令相关知识