Bpazy / blog

我的博客,欢迎关注和讨论
https://github.com/Bpazy/blog/issues
MIT License
41 stars 2 forks source link

grep 命令 #253

Open Bpazy opened 2 years ago

Bpazy commented 2 years ago

记录一些 grep 命令相关知识

Bpazy commented 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一番后找到数篇科普文,终于茅塞顿开,现总结如下。

正则表达式的类型

  1. 基本的正则表达式(Basic Regular Expression),又叫 Basic RegEx,简称 BREs
  2. 扩展的正则表达式(Extended Regular Expression),又叫 Extended RegEx,简称 EREs
  3. Perl 的正则表达式(Perl Regular Expression)又叫 Perl RegEx,简称PREs
常用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