今天看到個shell指令碼裡面awk處理字串的,裡面有一句gsub("\\.[0-9]+$","",$2),而這個$2的格式是2013-08-07 00:12:13.333這種,這個gsub想要把.333給去掉,看著不太正常,感覺裡面的正則式應該是匹配不到.333的啊。\\轉義後就變成了一個\,而原來的.是沒有被轉義的,這樣就應該無法截取掉.333的,可實際運行了一下,的確可以正確運行,然後又去掉一個\試了下,也可以,但是提示awk: warning: escape sequence `\.' treated
as plain `.'
查了下,應該是多次轉義的問題,有個講解是說的比較清楚的,轉載如下:
原始地址:http://pzy84.blogbus.com/logs/80017403.html
對於 AWK 程式中的pattern,用"//"包圍即可,比如
mount |awk '/type (ext3|tmpfs)/ {print $1}'
分隔字元(field separator)也支援Regex,它在 awk 程式中是一個名為 FS 的變數,可以在命令列中通過 -F 參數設定 FS 變數的值,比如
awk -F '[:/]' '{print $2}'
如果方括弧本身就是分隔字元,比如想提取日誌中用[]包圍的時間戳記,就需要非常小心地使用引號和轉義,因為shell會搶先轉義。
通過實驗,我發現這裡面有三層轉義,按執行順序依次是:
shell
awk
field separator processor
要禁止shell轉義,請用單引號包圍 FS 的值,否則使用雙引號或乾脆不用引號(僅當參數不包含空格時)。
awk的轉義是無法禁止的,所以只能通過累加轉義來抵消它的影響,也就是用 '\\' 表達 '\'。
field separator processor 是我想象出來的一個東西,總之我們的目的就是讓 FS 的值正好就是最根本的那個Regex。
以下是一些樣本,正反面都有。樣本程式的任務是從"[234 abc] lalala"中提取出"234 abc"。
(1) 失敗,"[\[\]]" 被 awk 轉義成 "[[]]" 了
[pzy@vm ~]$ echo "[234 abc] lalala" | awk -F '[\[\]]' '{print $2}'
awk: warning: escape sequence `\[' treated as plain `['
awk: warning: escape sequence `\]' treated as plain `]'
(2) 成功,"[\\[\\]]" 被 awk 轉義成 "[\[\]]" 了,而這正是我們想要的結果
[pzy@vm ~]$ echo "[234 abc] lalala" | awk -F '[\\[\\]]' '{print $2}'
234 abc
(3) 失敗,"[\\[\\]]" 先被 shell 轉移成 "[\[\]]",再被 awk 轉義成 "[[]]" 了
[pzy@vm ~]$ echo "[234 abc] lalala" | awk -F "[\\[\\]]" '{print $2}'
awk: warning: escape sequence `\[' treated as plain `['
awk: warning: escape sequence `\]' treated as plain `]'
(4) 成功,"[\\\\[\\\\]]" 先被 shell 轉義成 "[\\[\\]]",再被 awk 轉義成 "[\[\]]"
[pzy@vm ~]$ echo "[234 abc] lalala" | awk -F "[\\\\[\\\\]]" '{print $2}'
234 abc
(5) 成功,跟(4)的原理相同
[pzy@vm ~]$ echo "[234 abc] lalala" | awk -F [\\\\[\\\\]] '{print $2}'
234 abc
(6) 成功,原理我就不明白了,在論壇裡看到的,由它還可以衍生出很多變種
[pzy@vm ~]$ echo "[234 abc] lalala" | awk -F [][] '{print $2}'
234 abc