前言本博客中使用的示例文件a.txt內(nèi)容如下。 ID name gender age email phone 1 Bob male 28 abc@qq.com 18023394012 2 Alice female 24 def@gmail.com 18084925203 3 Tony male 21 aaa@163.com 17048792503 4 Kevin male 21 bbb@189.com 17023929033 5 Alex male 18 ccc@xyz.com 18185904230 6 Andy female 22 ddd@139.com 18923902352 7 Jerry female 25 exdsa@189.com 18785234906 8 Peter male 20 bax@qq.com 17729348758 9 Steven female 23 bc@sohu.com 15947893212 10 Bruce female 27 bcbd@139.com 13942943905 讀取數(shù)據(jù)的方式在講解文本處理工具awk之前我們需要先來看一下命令/工具從文件中讀取數(shù)據(jù)的幾種方式,大多數(shù)方式我們可以使用bash中的read命令來模擬,無法模擬的我們知道其思路也可以。 1、按字符數(shù)量讀取。每次根據(jù)指定的字符數(shù)量來讀取數(shù)據(jù)。 這里注意不要使用要使用-N而不是-n,這樣子才可以將空白字符、換行符等也讀入。在echo時(shí)使用雙引號包裹變量引用可以防止空格壓縮,前后使用3個(gè)中劃線“-”用來顯示變量頭尾,可以看出變量是否包含空白字符。 [root@c7-server ~]# read -N 4 char < a.txt
[root@c7-server ~]# echo "---$char---"
---ID ---
2、按字節(jié)數(shù)量(即數(shù)據(jù)大小)讀取。每次根據(jù)指定的字節(jié)數(shù)量來讀取數(shù)據(jù)。 3、按分隔符讀取。從文件開始處讀取數(shù)據(jù),遇到分隔符后停止,將讀取到的數(shù)據(jù)保存,下次讀取時(shí)從分隔符位置后繼續(xù)讀取,每次保存的數(shù)據(jù)中不會包含分隔符本身。 輸出結(jié)果的第3和第4行數(shù)據(jù)屬于同一次讀取的數(shù)據(jù),之所以換行是因?yàn)閿?shù)據(jù)本身包含了換行符。 [root@c7-server ~]# while read -d "m" chars; do echo "---$chars---"; done < a.txt
---ID na---
---e gender age e---
---ail phone
1 Bob---
---ale 28 abc@qq.co---
4、按行讀取。它可以理解為特殊的按分隔符讀取,即分隔符為換行符(\n)。 [root@c7-server ~]# while read line; do echo "---$line---"; done < a.txt
---ID name gender age email phone---
---1 Bob male 28 abc@qq.com 18023394012---
---2 Alice female 24 def@gmail.com 18084925203---
... ...
5、一次性讀取整個(gè)所有數(shù)據(jù)。它既可以理解為按無限大字符/字節(jié)數(shù)量讀取,也可以理解為按文件中不存在的字符作為分隔符讀取。 [root@c7-server ~]# read -N 10000 chars < a.txt
[root@c7-server ~]# echo "---$chars---"
---ID name gender age email phone
1 Bob male 28 abc@qq.com 18023394012
... ...
9 Steven female 23 bc@sohu.com 15947893212
10 Bruce female 27 bcbd@139.com 13942943905
---
[root@c7-server ~]# read -d "_" chars < a.txt
[root@c7-server ~]# echo "---$chars---"
---ID name gender age email phone
1 Bob male 28 abc@qq.com 18023394012
... ...
9 Steven female 23 bc@sohu.com 15947893212
10 Bruce female 27 bcbd@139.com 13942943905---
用法入門awk 'awk_program' a.txt b.txt a.txt a.txt:awk命令所要讀取的文件,文件可以一個(gè)或者多個(gè),也可以重復(fù)。文件數(shù)也可以是0個(gè),即從標(biāo)準(zhǔn)輸入中獲取數(shù)據(jù)。awk并不會將操作直接作用于文件,僅僅是讀取文件數(shù)據(jù)對其進(jìn)行操作,不會修改源文件。 'awk_program':單引號包裹的內(nèi)容叫做awk代碼/命令/程序。awk看似是一個(gè)命令,實(shí)則是一門編程語言,因此將其命令稱之為代碼也是合理的。 awk代碼既可以使用單引號包裹,又可以使用雙引號,但是在幾乎所有情況下都使用單引號。因?yàn)樵诖a中會使用一些諸如“$”這類特殊符號,它既可以被bash解釋又可以被awk解釋,如果使用雙引號那么它們就會被bash解釋了,為了將它保留給awk解釋所以我們才要使用單引號。 awk代碼中??梢姟皗...}”符號,這個(gè)表示的是代碼/語句塊,塊和塊之間使用{}分隔,在CLI中同一個(gè)語句塊內(nèi)部的多個(gè)語句使用分號“;”分隔。如果將代碼寫在文件中,在CLI中使用-f選項(xiàng)調(diào)用的話,則不需要使用分號“;”分隔塊內(nèi)語句。 接下來我們來看2個(gè)示例。 [root@c7-server ~]# awk '{print $0}' a.txt
ID name gender age email phone
1 Bob male 28 abc@qq.com 18023394012
... ...
10 Bruce female 27 bcbd@139.com 13942943905
[root@c7-server ~]# awk '{print $0}{print "Hello";print "world."}' a.txt
ID name gender age email phone
Hello
world.
1 Bob male 28 abc@qq.com 18023394012
Hello
world.
... ...
10 Bruce female 27 bcbd@139.com 13942943905
Hello
world.
在默認(rèn)情況下,awk按行讀取數(shù)據(jù),每讀取一行就會將整行的內(nèi)容保存至$0。然后對每一行的數(shù)據(jù)都執(zhí)行一次{}代碼塊中的指令,print指令似于bash的echo命令。因此:
BEGIN和END代碼塊上文提到的代碼塊,是在每次awk讀入一行(默認(rèn))數(shù)據(jù)時(shí)需要執(zhí)行的操作,這類代碼塊我們可以將其稱之為main代碼塊,它們是awk的主體(main)代碼。 除了main代碼塊以外,awk還支持兩種代碼塊:BEGIN和END。 awk 'BEGIN{print "I am in the front."}{print "Hello world!"}' a.txt
awk '{print "Hello world!"}END{print "I am in the back."}' a.txt
awk 'BEGIN{print "I am in the front."}{print "Hello world!"}END{print "I am in the back."}' a.txt
萌新建議將上面的命令敲出來看結(jié)果感受一下。這次main代碼塊中我們沒有打印整行數(shù)據(jù)本身(print $0),而是打印與讀入數(shù)據(jù)無關(guān)的信息,來證實(shí)main代碼塊的工作機(jī)制。 BEGIN代碼塊:在讀入數(shù)據(jù)之前就會執(zhí)行的指令,且僅執(zhí)行1次。由于這個(gè)特性的存在,BEGIN代碼塊可以不需要讀入數(shù)據(jù)(文件或者STDIN),我們在測試某些awk特性的時(shí)候也可以僅使用BEGIN代碼塊。 ~]# awk 'BEGIN{print "I need no files and input."}'
I need no files and input.
由于是在讀入數(shù)據(jù)之前就會執(zhí)行,因此在BEGIN代碼塊中無法正常引用$0變量,和該變量類似的其他賦值方式相同的變量也無法正常引用。強(qiáng)行引用的話會是空字符串。因?yàn)檫@類變量的賦值均需要在有讀入數(shù)據(jù)的情況下。 END代碼塊:在所有數(shù)據(jù)讀取并執(zhí)行完main代碼塊之后會執(zhí)行的指令,且僅執(zhí)行1次。如果有END代碼塊,那么就必須有讀入數(shù)據(jù),若沒有則必須在STDIN鍵入Ctrl+d來表示EOF,否則awk命令會阻塞直到遇到EOF。 [root@c7-server ~]# awk 'END{print "aaaa"}' 1 2 3 aaaa 上面的輸出結(jié)果中,1、2和3是我鍵入的STDIN,由于沒有main代碼塊因此什么也沒有發(fā)生(無論是表面上來看還是awk運(yùn)行內(nèi)部)。而aaaa則是我鍵入Ctrl+d后,awk收到EOF,此時(shí)awk才執(zhí)行END代碼塊的內(nèi)容。 END代碼塊中可以引用$0類的變量,其值與讀入數(shù)據(jù)最后一行(默認(rèn))的數(shù)據(jù)相關(guān)。 [root@c7-server ~]# tail -n 1 a.txt
10 Bruce female 27 bcbd@139.com 13942943905
[root@c7-server ~]# awk 'END{print $0}' a.txt
10 Bruce female 27 bcbd@139.com 13942943905
一般來說,為了看起來更舒服,我們一般將BEGIN寫在main之前(左側(cè)),END寫在main之后(右側(cè)),中間有一個(gè)或者多個(gè)main。 代碼塊中的指令可以為空(即沒有,啥也不干)。main代碼塊為空的話則可以連大括號都省略了。 awk 'BEGIN{}{}{}{}END{}' ....
awk 'BEGIN{}END{}' ....
更新awkawk這個(gè)工具最早是在1977年由3位大牛所編寫,工具名稱來源于三位程序員的名字:Alfred Aho、Peter Weinberger和Brian Kernighan。而我們現(xiàn)在在Linux上所使用的awk則是來源于GNU組織所改變的gawk,為了不改變大家的使用習(xí)慣,使用awk做了軟鏈接。 ~]# ls -l $(which awk)
lrwxrwxrwx 1 root root 30 Dec 13 17:32 /usr/bin/awk -> gawk
程序包名稱為gawk。 ~]# rpm -qa | grep "awk" gawk-4.0.2-4.el7_3.1.x86_64 教程作者使用的版本是4.2.0,因此為了后續(xù)實(shí)驗(yàn)的正確性我們需要使用4.2.0版本的awk。作者給出了更新方式。 wget --no-check-certificate https://mirrors.tuna./gnu/gawk/gawk-4.2.0.tar.gz
tar xf gawk-4.2.0.tar.gz
cd gawk-4.2.0/
./configure --prefix=/usr/local/gawk4.2 && make && make install
ln -fs /usr/local/gawk4.2/bin/gawk /usr/bin/awk
awk --version
gawk --version
當(dāng)我們想使用4.2.0版本的awk的時(shí)候直接鍵入awk命令,想使用4.0.2舊版本的awk時(shí)則鍵入gawk命令。在我撰寫本博客的時(shí)候,GNU awk官方的documentation已經(jīng)更新到5.1的了。 |
|