grep 正则表达式用引号括起来和元字符加反斜杠转义的测试

grep 正则表达式用引号括起来和元字符加反斜杠转义的测试html

实验在 grep 命令中的表达式:不加引号,加单引号,加双引号的区别,以及部分元字符前加与不加 `\’ 进行转义的区别。实验环境为“实验楼( http://www.shiyanlou.com/ )上的 CentOS 6 ,GNU grep 2.6.3。linux

一、测试不把 grep 的表达式加上引号:正则表达式


[root@d9a69d7b11ac test]#mkdir test; cd test; touch hello
[root@d9a69d7b11ac test]# bash -x -c "ls ./* | grep hell*"
+ ls ./hello
+ grep hello
./hello
[root@d9a69d7b11ac test]# touch hello2
[root@d9a69d7b11ac test]# bash -x -c "ls ./* | grep hell*"
+ ls ./hello ./hello2
+ grep hello hello2
[root@d9a69d7b11ac test]# echo "hello3" > hello2
[root@d9a69d7b11ac test]# bash -x -c "ls ./* | grep hell*"
+ ls ./hello ./hello2
+ grep hello hello2
hello3
[root@d9a69d7b11ac test]#

shell

可见,若是 grep 的表达式不加引号,碰到通配符等就会由于 bash 的扩展功能,而先把表达式进行扩展,扩展的结果再送入表达式进行grep 的命令执行。express

二、bash

下面测试把 grep 的表达式加上单引号括起来的状况:ide


[root@d9a69d7b11ac test]# rm hello2
rm: remove regular empty file `hello2'? y
[root@d9a69d7b11ac test]# ls
hello
[root@d9a69d7b11ac test]# bash -x -c "ls ./* | grep 'hell*'"
+ grep 'hell*'
+ ls ./hello
./hello
[root@d9a69d7b11ac test]# bash -x -c "ls ./* | grep 'hell*'"
+ ls ./hello
+ grep 'hell*'
./hello
[root@d9a69d7b11ac test]# bash -x -c "ls ./* | grep 'hell*'"
+ grep 'hell*'
+ ls ./hello
./hello
[root@d9a69d7b11ac test]# touch hello2
[root@d9a69d7b11ac test]# bash -x -c "ls ./* | grep 'hell*'"
+ ls ./hello ./hello2
+ grep 'hell*'
./hello
./hello2
[root@d9a69d7b11ac test]# echo "hello3" > hello2
[root@d9a69d7b11ac test]# bash -x -c "ls ./* | grep 'hell*'"
+ ls ./hello ./hello2
+ grep 'hell*'
./hello
./hello2
[root@d9a69d7b11ac test]#

测试

可见,grep 表达式用单引号括起来就避免了 bash 的预先扩展。lua

可是,要注意,bash -x 的展开功能的展开顺序不是固定的,如上,有时先展开 ls ./*,有时先展开 grep ‘hell*’(由于是加的单引号,因此展开后保持不变。)。可是,展开后的执行是先执行 ls ./* ,结果再传给 grep ‘hell*’ 执行的。spa

三、

下面测试把 grep 的表达式加双引号括起来的状况:


[root@d9a69d7b11ac test]# rm hello2
rm: remove regular empty file `hello2'? y
[root@d9a69d7b11ac test]# ls
hello
[root@d9a69d7b11ac test]# bash -x -c "ls ./* | grep "hell*""
+ ls ./hello
+ grep hello
./hello
[root@d9a69d7b11ac test]# bash -x -c 'ls ./* | grep "hell*"'
+ ls ./hello
+ grep 'hell*'
./hello
[root@d9a69d7b11ac test]# touch hello2
[root@d9a69d7b11ac test]# bash -x -c "ls ./* | grep "hell*""
+ ls ./hello ./hello2
+ grep hello hello2
[root@d9a69d7b11ac test]# bash -x -c 'ls ./* | grep "hell*"'
+ ls ./hello ./hello2
+ grep 'hell*'
./hello
./hello2
[root@d9a69d7b11ac test]# ls ./* | grep "hell*"
./hello
./hello2
[root@d9a69d7b11ac test]# echo "hello3" > hello2
[root@d9a69d7b11ac test]# bash -x -c "ls ./* | grep "hell*""
+ grep hello hello2
+ ls ./hello ./hello2
hello3
[root@d9a69d7b11ac test]# bash -x -c 'ls ./* | grep "hell*"'
+ ls ./hello ./hello2
+ grep 'hell*'
./hello
./hello2
[root@d9a69d7b11ac test]# ls ./* | grep "hell*"
./hello
./hello2
[root@d9a69d7b11ac test]# bash -x -c 'a="he"; ls ./* | grep "${a}ll*"'
+ a=he
+ ls ./hello ./hello2
+ grep 'hell*'
./hello
./hello2
[root@d9a69d7b11ac test]# bash -x -c 'a="he"; ls ./* | grep '${a}ll*''
+ a=he
+ ls ./hello ./hello2
+ grep 'll*'
./hello
./hello2
./hello2
[root@d9a69d7b11ac test]# a=he; ls ./* | grep '${a}ll*'
[root@d9a69d7b11ac test]# a=he; ls ./* | grep "${a}ll*"
./hello
./hello2
[root@d9a69d7b11ac test]# bash -x -c 'a="he"; ls ./* | grep ${a}ll*'
+ a=he
+ ls ./hello ./hello2
+ grep hello hello2
hello3
[root@d9a69d7b11ac test]# a="he"; ls ./* | grep ${a}ll*
hello3
[root@d9a69d7b11ac test]#

能够看出,grep 的表达式加上双引号,能够避免一部分 bash 扩展功能,如 ls ./* | grep “hell*” 中 grep 表达式中的 *;可是不能避免变量扩展,如能够扩展:a=”he”; ls ./* | grep “${a}ll*”。

另外,在测试 bash -x -c ‘a=”he”; ls ./* | grep ‘${a}ll*” 和 a=he; ls ./* | grep ‘${a}ll*’ 时,咱们看见了不同的结果,具体缘由不明,有多是 bash -c 的功能对’${a}ll*’做了一些修改?

另外,虽然暂时看来在 grep 中的表达式用双引号括起来彷佛能够利用它扩展变量的功能把 grep 的正则表达式弄成变量,可是,这个功能有没有其它的反作用呢?目前没有查找到相关的文档依据,因此保险的作法是:在 grep 的正则表达式中只用单引号括起来。这种作法也是 grep 的 info 文档中的例子所采用的。

四、

实验一下 grep 使用基本正则表达式时,部分元字符必须加上转义 \ 的状况:

在 info grep 的菜单:* Regluar Expressions:: ->Basic vs Extended:: 中写道:

 

3.6 Basic vs Extended Regular Expressions=========================================

In basic regular expressions the meta-characters `?’, `+’, `{’, `|’,

`(’, and `)’ lose their special meaning; instead use the backslashed

versions `\?’, `\+’, `\{’, `\|’, `\(’, and `\)’.

因此,必须在 grep 的正则表达式中使用 \ 以使这些字符的做用生效。以下(继续使用上面的测试环境):


[root@e16578371323 test]# ls
hello hello2
[root@e16578371323 test]# ls ./* | grep 'hell?'
[root@e16578371323 test]# ls ./* | grep 'hell\?'
./hello
./hello2
[root@e16578371323 test]# ls ./* | grep 'hel{2}'
[root@e16578371323 test]# ls ./* | grep 'hel\{2\}'
./hello
./hello2
[root@e16578371323 test]#

五、

结论:在使用 grep 时,正则表达式必定要用单引号括起来,不然可能由于 shell 执行环境的预先展开功能致使错误;在基本正则表达式(grep 默认为基本正则表达式)中的元字符 `?’, `+’, `{’, `|’,`(’, `)’ 前面必定要加上 `\’ 进行转义。另外,注意区分通配符`?’, `*’, `[]‘ 与正则表达式中相应字符的含义和用法。

欢迎交流探讨,如有错漏,敬请批评与斧正。谢谢。

相关文章
相关标签/搜索