sed和gawk介紹
知識體系:
#使用文本文件
#探索sed
#探索gawk
shell腳本可以把處理文本中包含的所有類型的數據這樣的普通任務自動化。然而,只使用shell腳本命令處理文本文件的內容卻有些麻煩。如果要 在shell腳本中進行任何類型的數據處理,就要熟悉linux中現有的sed和gawk工具了。因為這兩個命令行編輯器能夠方便地格式化、插入、修改和刪除文本元素。
1、文本處理
1.1、sed編輯器
sed編輯器稱為流編輯器(stream editor),能根據在vim、vi等編輯器處理數據之前事先提供的規則集編輯數據流。它每次從輸入讀取一行數據,將該數據與所提供的編輯器命令進行匹配,根據命令修改數據流中的數據,然後將新數據輸出到STDOUT。
使用sed命令格式:
sed option xxx(script file)
options參數允許自定義sed命令的行為,如下表:
***********************************************************
選項 描述
-e script 將腳本中指定的命令添加到處理輸入時執行的命令中
-f file 將文件中指定的命令添加到處理輸入時執行的命令中
-n 不需要為每個命令產生輸出,但要等待打印命令
***********************************************************
1.1.1、在命令行中定義編輯器命令
默認情況下,sed編輯器將指定的命令應用於STDIN輸入流,這就允許將數據直接管道傳送給sed編輯器處理,如下例子:
[[email protected] ~]# echo "welcome to tencent" | sed 's/tencent/linuxidc/'
welcome to linuxidc
該例在sed編輯器中使用了s命令,表示說第二個文本字符替換第一個兩個斜槓之間的文本字符,如上通過linuxidc替換了tencent。
當然,如上只是編輯了一行數據,在一個數據文件中也可以通過sed處理:
[[email protected] ~]# cat testfile
welcome to http://www.linuxidc.com
welcome to http://www.linuxidc.com
welcome to http://www.linuxidc.com
[[email protected] ~]# sed 's/blog/6688.cc/' testfile
welcome to http://www.6688.cc
welcome to http://www.6688.cc
welcome to http://www.6688.cc
或者通過cat借助管道查看:
[[email protected] ~]# cat testfile | sed 's/blog/6688.cc/'
welcome to http://www.6688.cc
welcome to http://www.6688.cc
welcome to http://www.6688.cc
sed命令執行與返回數據幾乎同時進行,但是sed編輯器並不修改文本文件中的數據,它只是把文本內容修改後發送到STDOUT,原文本文件沒有改動過。
[[email protected] ~]# cat testfile
welcome to http://www.linuxidc.com
welcome to http://www.linuxidc.com
welcome to http://www.linuxidc.com
1.1.2、在命令行中使用多個編輯器命令
要從sed命令行執行多個命令,只需要使用-e選項:
[[email protected] ~]# sed -e 's/blog/www/;s/linuxidc/linxidc/' testfile
welcome to http://www.linxidc.com
welcome to http://www.linxidc.com
welcome to http://www.linxidc.com
兩個命令同時應用於文件中的每一行數據,命令必須使用分號隔開。
當然,也可以使用此提示符,而不用分號分隔命令:
[[email protected] ~]# sed -e '
> s/blog/www/
> s/linuxidc/wzp/' testfile
welcome to http://www.linuxidc.net
welcome to http://www.linuxidc.net
welcome to http://www.linuxidc.net
這裡需要注意的是:要在後單引號出現的這一行完成整個命令,因為bash檢測到後引號後就處理命令。
1.1.3、從文件讀取編輯器命令
如果說,有太多的sed命令要處理,那麼可以將他們保存在一個獨立的文件中,然後在使用sed命令時候使用-f選項指定文件,如下例:
[[email protected] ~]# cat script24
s/blog/www/
s/linuxidc/idcfree/
這裡不需要使用分號和單引號了,sed編輯器將每一行視為單獨一個命令。
[[email protected] ~]# sed -f script24 testfile
welcome to http://www.idcfree.com
welcome to http://www.idcfree.com
welcome to http://www.idcfree.com
通過調用script24這個預先指定好的文件就可以實現數據的處理。
1.2、gawk程序
盡管sed編輯器是動態修改文本文件的便利工具,但它也有自己的局限性,這個時候就可以借助更高級、能夠提供類似於編程環境的工具,它允許修改和組織文件中的數據。
gawk程序是unix中原awk程序的GNU版本,它提供一種編程語言而不僅僅是編輯器命令。
1.2.1、gawk命令格式
gawk options xxx(program file)
如下是gawk程序的可用選項:
***********************************************************
選項 描述
-F fs 指定描繪一行中數據字段的文件分隔符
-f file 指定讀取程序的文件名
-v var=value 定義gawk程序中使用的變量和默認值
-mf N 指定數據文件中要處理的字段的最大數目
-mr N 指定數據文件中的最大記錄大小
-W keyword 指定gawk的兼容模式或警告級別
***********************************************************
1.2.2、自命令行讀取程序腳本
gawk程序腳本由左大括號和右大括號定義,腳本命令必須放置在兩個大括號之間,如下載命令行上指定的一個簡單gawk程序腳本:
[[email protected] ~]# gawk '{print "hello world!"}'
改程序定義了一個print命令才執行打印功能,將文本hello world!輸出到STDOUT。然而,執行本命令不會發生任何顯示信息。因為命令行中沒有定義文件名,所以gawk程序要從STDIN獲取數據,比如你隨意輸入任何內容,按回車鍵既可以實現print功能:
[[email protected] ~]# gawk '{print "hello world!"}'
try to test and enter
hello world!
test again
hello world!
同sed編輯器完全一樣,gawk程序對數據流中可用的每一行文本執行程序腳本。由於本程序腳本設定為顯示固定的文本字符串,所以無論數據流中輸入什麼,都得到相同的輸出。如果要結束gawk程序,必須發送信號說明數據流已經結束。bash shell提供了生成end-of-file(EOF)字符的組合鍵來發送結束信號。在bash中,Ctrl+D組合鍵生成EOF字符。
1.2.3、使用數據字段變量
gawk的主要功能之一就是處理文本文件中數據的能力,它通過自動將變量分配給每行中的每個數據元素實現這一功能。默認情況下,gawk將下面的變量分配給在文本行中檢測到的每個數據字段:
* $0表示整行文本;
* $1表示文本行中的第一個數據字段;
* $2表示文本行中的第二個數據字段;
* $n表示文本行中的第n個數據字段;
各個數據段是根據文本行中的字段分隔符(默認是空格)確定的,如下通過gawk程序讀取文本文件的數據段:
[[email protected] ~]# cat test1
one line of test file
two line of test file
three line of test file //(故意在three後面留兩個空格)
[[email protected] ~]# gawk '{print $1}' test1
one
two
three
通過$1字段變量即可顯示每行文本的第一個字段;
[[email protected] ~]# gawk '{print $2}' test1
line
line
line
你會發現,上面兩個空格都被視為一個分隔符了,即把第二個字段顯示出來。
當我們要修改默認的分隔符的時候可以使用-F選項,比如把分隔符改成冒號來讀取/etc/passwd文件:
[[email protected] ~]# tail -3 /etc/passwd
webalizer:x:67:67:Webalizer:/var/www/usage:/sbin/nologin
sabayon:x:86:86:Sabayon user:/home/sabayon:/sbin/nologin
mysql:x:27:27:MySQL Server:/home/mysql:/sbin/nologin
我們取最後三行來看,我們知道/etc/passwd就是以冒號來分隔每個字段的,所以我們要通過gawk查看指定某些字段時候就必須通過-F選項修改默認分隔符為冒號:
[[email protected] ~]# tail -3 /etc/passwd | gawk -F: '{print $1,$6,$7}'
webalizer /var/www/usage /sbin/nologin
sabayon /home/sabayon /sbin/nologin
mysql /home/mysql /sbin/nologin
這樣我們就把第一、第六、第七個字段顯示出來了。
1.2.4、在程序腳本中使用多個命令
有時候我們需要在命令行指定的腳本中使用多個命令,只需要在各命令之間加一個分號:
[[email protected] ~]# echo "welcome to linuxidc" | gawk '{$3="bbs.linuxidc"; print $0}'
welcome to bbs.linuxidc
第一個命令為$3字段指定為bbs.linuxidc,第二個命令為打印整個數據字段。
當然,這裡也可以通過此提示符每次輸入一行程序腳本命令:
[[email protected] ~]# gawk '{
> $3="bbs.linuxidc"
> print $0}'
welcome to linuxidc
welcome to bbs.linuxidc
welcome to netease
welcome to bbs.linuxidc
當把gawk '{ $3="bbs.linuxidc"; print $0}'寫好後,輸入的任何內容,第二個字段都被修改成bbs.linuxidc
如果要結束程序,可以使用ctrl+d組合鍵發送結束信號。
1.2.5、從文件讀取程序
同sed編輯器一樣,gawk編輯器允許將程序保存在文件中並在命令行中引用:
[[email protected] ~]# cat script24
{ print $5 "'s userrid is " $1}
[[email protected] ~]# tail -3 /etc/passwd | gawk -F: -f script24
Webalizer's userrid is webalizer
Sabayon user's userrid is sabayon
MySQL Server's userrid is mysql
當然,被調用的文件可以指定多個命令,則使得每行放置一個命令而不需要使用分號:
[[email protected] ~]# cat script25
{
text="'s userid is"
print $5 text $1
}
[[email protected] ~]# tail -3 /etc/passwd | gawk -F: -f script25
Webalizer's userid iswebalizer
Sabayon user's userid issabayon
MySQL Server's userid ismysql
我們可以看到得到的結果是一樣的,不過有點需要注意的是gawk程序不像shell腳本不需要使用美元符號引用變量值,所以直接用print命令顯示結果。
1.2.6、在處理數據之前運行腳本
gawk程序還允許指定運行腳本的時間。默認情況下,gawk從輸入讀取一行文本,然後執行程序腳本處理文本行中的數據。但有時需要在處理數據之前運行腳本,就必須使用BEGIN關鍵字了,如下:
[[email protected] ~]# gawk 'BEGIN {print "hello world!"}'
hello world!
print命令將在讀取數據之前顯示文本,不過它在顯示該文本之後迅速退出而不等待數據輸入。
1.2.7、在處理數據之後運行腳本
與BEGIN關鍵字類似,END關鍵字允許指定在讀取數據之後gawk執行的程序腳本:
[[email protected] ~]# gawk 'BEGIN {print "hello world!" }{print $0} END {print "goodbye"}'
hello world!
this is a test
this is a test
i would enter ctrl+d
i would enter ctrl+d
goodbye
執行程序開始就print出hello world!字符,接著輸入的任何數據都通過$0回顯一次,當我ctrl+d結束程序的時候,程序就print出goodbye字符。所以,通過這種方法非常適合創建數據報告。