linux中grep 的详细用法已经有许多人介绍过了,本文是作者在学习过程中的总结和对原文中一些没有被提及或者含糊不清的概念的理解。
一、grep概述
grep的全称是global regular expression print,即全局正则表达式显示,grep接受一个字符串,在全文中搜索这个字符串或这个字符串表达的正则表达式。上面这句话有两个关键点:
1. 正则表达式本质上是一个字符串,例如"a*b",当一个字符串被当作正则表达式,其中的一些文本字符,如“*”等,就变为了正则表达式的元字符。
2. grep函数接受一个字符串,并把它当作正则表达式。
二、文本字符,元字符,通配符的区别
一个字符串中所有字符都是文本字符,当它被当作正则表达式用于文本检索时,其中的一些文本字符就变为了正则表达式特有的元字符;当它被用作检索文件名,其中的一些文本字符就变为了shell可以识别的通配符。总结如下:
1. 字符+元字符 = 正则表达式,用于文本的检索
2. 字符+通配符 = 用于文件或目录的检索
下表列出了全部元字符,和部分通配符。可以看到元字符和通配符有一部分是重合的,但是他们的表达的含义却不一定相同,例如中括号[ ]在两边表示的意思都是“匹配中括号里的任意一个”,而星号“*”当作元字符时表示“匹配任意个星号前面的字符”,而当作通配符时表示“匹配任意个任意字符”。
元字符 |
通配符 |
^ $ . [ ] { } - ? * + ( ) | \ |
* ? [ ] \ [^] [[:digit:]] |
注:通配符中[[:digit:]]表示匹配一个数字,诸如此类的还有[[:space:]]表示匹配一个空格等等。
三、使用grep为什么要对字符串加引号?
因为这部分又可以当作元字符又可以当作通配符的字符,有些情况下shell会错误的将一个字符当作通配符或元字符,因此grep的字符串的输入最好加上引号。
下面说明一种shell错误识别元字符和通配符的情况。当输入的字符串中包含空格,shell会将空格后的字符串当作需要检索的第一个文件,而将其中的元字符当作通配符。
加引号不是强制的,而是为了避免未预见的麻烦。
四、加引号加单引号和双引号有什么区别?
这里的区别就是一般Linux教程说明的单引号和双引号的区别:单引号不对文本处理,所有字符都是普通的字符,双引号将其中的$,\,`视为特殊的字符。
从上图可以看出,双引号中用实际的值替换$标注变量val,用命令的执行的结果替换倒引号``括起来的命令,用转义的结果替换反斜杠\后的字符,而单引号什么都不做。
前面第一节说到,grep的输入是一个字符串,纯文本,那么如果用双引号,双引号中的$\`的替换是优先于grep检索的,也是说双引号中字符串的执行结果才是grep的输入字符串。一般的过程是:先由双引号进行内部替换和倒引号执行,得到纯文本的字符串,再将字符串作为grep,fgrep,egrep的输入。
上图可以看出,双引号中的第1,3个反斜将第2,4个转义后相当于单引号括起来的‘a\\’。要表示匹配‘a\’,单引号只需要两个反斜杠,而双引号需要四个,因此无特殊需求为方便起见建议直接用单引号。
附:三种引号:倒引号`,单引号',双引号",倒引号将其中字符当作shell指令,单引号当作纯字符串,双引号也是当作字符串,不过会将其中的变量引用$,命令`(倒引号包含的字符串),转义符\这三者自动替换成变量引用的结果,命令的执行结果,转义后的结果后再当作一个字符串。
五、元字符和扩展元字符
扩展的元字符是在一般正则表达式中无法识别,grep只能识别一般元字符,把扩展的元字符当作一般字符。
扩展元字符“?”表示“匹配0或1个前面的字符”,上图可以看出grep不认识扩展元字符“?”,而将他当作普通字符,用“\”可以将元字符变为扩展元字符(如2),或者直接用扩展元字符的模式搜索(如3)。
六、grep,egrep和fgrep
fgrep 将字符串当作一般字符,即取消任何元字符的特殊含义,但不能阻止双引号对其内部特殊字符的解释。
grep 将字符串当作一般字符和元字符。
egrep 将字符串当作一般字符、元字符和扩展元字符。
七、在grep中反斜杠\作用
1. 作用于文本字符:变为扩展元字符(仅用于grep不能识别而当作普通字符的扩展元字符)。
2. 作用于元字符:变为文本字符,取消特殊含义。(这里也可以用方括号[ ]变为普通字符,例如[\]就相当于匹配一个反斜杠)
若有问题可以评论区交流,谢谢。