grep 正則表達式用引號括起來和元字符加反斜杠轉義的測試


grep 正則表達式用引號括起來和元字符加反斜杠轉義的測試

實驗在 grep 命令中的表達式:不加引號,加單引號,加雙引號的區別,以及部分元字符前加與不加 `\’ 進行轉義的區別。實驗環境為“實驗樓( http://www.shiyanlou.com/ )上的 CentOS 6 ,GNU grep 2.6.3。

1、測試不把 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]#

可見,如果 grep 的表達式不加引號,碰到通配符等就會因為 bash 的擴展功能,而先把表達式進行擴展,擴展的結果再送入表達式進行grep 的命令執行。

2、

下面測試把 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*'"
+ 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 的預先擴展。

但是,要注意,bash -x 的展開功能的展開順序不是固定的,如上,有時先展開 ls ./*,有時先展開 grep ‘hell*’(因為是加的單引號,所以展開后保持不變。)。但是,展開后的執行是先執行 ls ./* ,結果再傳給 grep ‘hell*’ 執行的。

3、

下面測試把 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 文檔中的例子所采用的。

4、

實驗一下 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]#

5、

結論:在使用 grep 時,正則表達式一定要用單引號括起來,否則可能因為 shell 執行環境的預先展開功能導致錯誤;在基本正則表達式(grep 默認為基本正則表達式)中的元字符 `?’, `+’, `{’, `|’,`(’, `)’ 前面一定要加上 `\’ 進行轉義。另外,注意區分通配符`?’, `*’, `[]‘ 與正則表達式中相應字符的含義和用法。

歡迎交流探討,若有錯漏,敬請批評與斧正。謝謝。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM