Awk是一種非常通用的編程語言关筒,用于處理文件溶握。我們將只教您足夠的理解這一頁中的例子,再加上一個smidgen蒸播。
為什么學(xué)習(xí)AWK ?
和grep睡榆、sed一樣,AWK是UNIX shell編程的另一個基礎(chǔ)袍榆。
AWK有三種變體:
- AWK - the (very old) original from AT&T
- NAWK - A newer, improved version from AT&T
- GAWK - The Free Software foundation's version
最初胀屿,我不打算討論NAWK,但是一些UNIX供應(yīng)商已經(jīng)用NAWK替換了AWK包雀,而且兩者之間存在一些不兼容之處宿崭。如果我不警告你們這些不同之處,那就太殘忍了才写。所以當(dāng)我講到這些的時候葡兑,我會強(qiáng)調(diào)一下。重要的是要知道赞草,所有AWK的功能都在NAWK和GAWK中讹堤。NAWK的大部分功能(如果不是全部的話)都在GAWK中。NAWK是Solaris的一部分厨疙。GAWK 則不是洲守。然而,Internet上的許多站點(diǎn)都有免費(fèi)的資源沾凄。如果你使用Linux梗醇,你有了GAWK。但一般來說搭独,假設(shè)我說的是經(jīng)典的AWK婴削,除非另有說明。
為什么AWK如此重要?它是一個優(yōu)秀的過濾器和報告編寫器牙肝。許多UNIX程序生成行和列信息。AWK是處理這些行和列的優(yōu)秀工具嗤朴,并且比大多數(shù)傳統(tǒng)編程語言更容易使用AWK配椭。它可以被認(rèn)為是一個偽C解釋器,因?yàn)樗斫馀cC相同的算術(shù)運(yùn)算符雹姊。AWK還具有字符串操作函數(shù)股缸,因此它可以搜索特定的字符串并修改輸出。AWK也有關(guān)聯(lián)數(shù)組吱雏,這是非常有用的敦姻,也是大多數(shù)計(jì)算語言所缺乏的特性瘾境。關(guān)聯(lián)數(shù)組可以使復(fù)雜的問題變得簡單。
我將試著介紹基本的部分或AWK镰惦,并提到擴(kuò)展/變體迷守。“new AWK”或“nawk”出現(xiàn)在太陽系統(tǒng)上旺入,您可能會發(fā)現(xiàn)它在許多方面都優(yōu)于舊AWK兑凿。特別是,它有更好的診斷茵瘾,并且不會打印出原始AWK容易輸出的臭名昭著的“在行附近進(jìn)行救援”消息礼华。相反,“nawk”打印出它不理解的行拗秘,并用箭頭突出顯示不好的部分圣絮。GAWK 也會如此,這真的很有幫助。如果你發(fā)現(xiàn)自己需要一個功能,在AWK是非常困難的或不可能的,我建議你使用NAWK,GAWK,或者使用“a2p”轉(zhuǎn)換程序把你的AWK腳本轉(zhuǎn)換成PERL雕旨。PERL是一種了不起的語言扮匠,我一直在使用它,但是我不打算在這些教程中介紹PERL奸腺。我已經(jīng)表明了我的意圖餐禁,我可以問心無愧地繼續(xù)下去。
許多UNIX實(shí)用程序都有奇怪的名稱突照。AWK就是其中之一帮非。它不是awkward的縮寫。事實(shí)上讹蘑,它是一種優(yōu)雅而簡單的語言末盔。作品“AWK”來源于該語言的三個開發(fā)者的首字母:A. Aho, B. W. Kernighan和P. Weinberger。
基本結(jié)構(gòu)
AWK程序的基本組織形式如下:
pattern { action }
模式(pattern)指定何時執(zhí)行操作座慰。與大多數(shù)UNIX實(shí)用程序一樣陨舱,AWK是面向行的。也就是說版仔,模式指定了一個測試游盲,該測試以每一行讀取為輸入來執(zhí)行。如果條件為真蛮粮,則采取操作益缎。默認(rèn)模式匹配每一行。這是空白或null模式然想。另外兩個重要的模式由關(guān)鍵字“BEGIN”和“END”指定莺奔。如您所料,這兩個詞指定了在讀取任何行之前和讀取最后一行之后要執(zhí)行的操作变泄。AWK程序如下:
BEGIN { print "START" }
{ print }
END { print "STOP" }
在輸入文件之前和之后分別添加一行令哟。這不是很有用恼琼,但通過一個簡單的改變,我們可以把它變成一個典型的AWK程序:
BEGIN { print "File\tOwner"}
{ print $8, "\t", $3}
END { print " - DONE -" }
在下一節(jié)中屏富,我將改進(jìn)這個腳本晴竞,但是我們將它稱為“FileOwner”。但我們先不把它放到腳本或文件中役听。我將稍微介紹一下這部分颓鲜。等一下,跟著我典予,這樣你就能嘗到AWK的味道了甜滨。
字符“\t”表示制表符,因此輸出在偶數(shù)邊界上對齊瘤袖∫履Γ“3”的含義類似于shell腳本。不是第8和第3個參數(shù)捂敌,而是輸入行的第8和第3個字段艾扮。您可以將字段視為一列,您指定的操作對每一行列進(jìn)行操作占婉。
AWK和處理雙引號內(nèi)字符的shell之間有兩個不同之處泡嘴。AWK可以理解像“t”這樣跟在“\”字符后面的特殊字符。Bourne和C UNIX shell則不理解逆济。另外酌予,與shell(和PERL)不同,AWK不計(jì)算字符串中的變量奖慌。為了解釋抛虫,第二行不能這樣寫:
{print "$8\t$3" }
該示例將打印“3”。在引號內(nèi)简僧,$符號不是一個特殊字符建椰。在外部,它對應(yīng)一個字段岛马。我說的第三和第八個字段是什么意思?考慮Solaris“/usr/bin/ls -l”命令棉姐,它有8列信息。System V版本(類似于Linux版本)啦逆,“/usr/5bin/ls -l”有9列谅海。第三列是所有者,第八列(或第九列)是文件名稱蹦浦。這個AWK程序可以用來處理“l(fā)s -l”命令的輸出,打印出每個文件的文件名撞蜂,然后是所有者盲镶。我來教你怎么做侥袜。
更新:在linux系統(tǒng)上,將“9”溉贿。
關(guān)于使用符號表示接下來的單詞是變量的名稱宇色。Awk是不同的九杂。”有不同的含義例隆。因此,下面的代碼將打印兩個“字段”以進(jìn)行標(biāo)準(zhǔn)輸出抢蚀。打印的第一個字段是數(shù)字“5”镀层,第二個字段是輸入行上的第五個字段(或列)。
BEGIN { x=5 }
{ print x, $x}
執(zhí)行AWK腳本
讓我們開始編寫第一個AWK腳本皿曲。有幾種方法可以做到這一點(diǎn)唱逢。
假設(shè)第一個腳本名為“FileOwner”,那么調(diào)用將是
ls -l | FileOwner
如果當(dāng)前目錄中只有兩個文件屋休,則可能生成以下內(nèi)容:
File Owner
a.file barnett
another.file barnett
- DONE -
這個腳本有兩個問題坞古。這兩個問題都很容易解決,但是我將在介紹基本知識之前暫時不討論這個問題劫樟。
腳本本身可以用多種方式編寫痪枫。我已經(jīng)展示了C shell (csh/tcsh)和Bourne/Bash/POSIX shell腳本。C shell版本應(yīng)該是這樣的:
#!/bin/csh -f
# Linux users have to change $8 to $9
awk '\
BEGIN { print "File\tOwner" } \
{ print $8, "\t", $3} \
END { print " - DONE -" } \
'
當(dāng)然毅哗,一旦您創(chuàng)建了這個腳本听怕,您需要使這個腳本可執(zhí)行:
chmod +x awk_example.1.csh
test:
ls -l | sh FileOwner
正如您在上面的腳本中看到的,如果不是腳本的最后一行虑绵,AWK腳本的每一行都必須有一個反斜杠尿瞭。這是必要的,因?yàn)槟J(rèn)情況下翅睛,C shell不允許字符串超過一行声搁。我有一長串關(guān)于使用C shell的抱怨。
Bourne shell(和大多數(shù)shell一樣)允許引用字符串跨越幾行:
!/bin/sh
# Linux users have to change $8 to $9
awk '
BEGIN { print "File\tOwner" }
{ print $8, "\t", $3}
END { print " - DONE -" }
再次說明捕发,一旦它被創(chuàng)建疏旨,它必須是可執(zhí)行的:
chmod +x awk_example1.sh
順便說一下,我在教程中給出了示例腳本扎酷,并在文件名上使用擴(kuò)展名來指示腳本的類型檐涝。當(dāng)然,您可以通過輸入以下代碼把腳本“install”到您的home“bin”目錄中:
cp awk_example1.sh $HOME/bin/awk_example1
chmod +x $HOME/bin/awk_example1
第三種類型的AWK腳本是“原生的”AWK腳本,其中不使用shell谁榜。您可以在文件中編寫命令并執(zhí)行:
awk -f filename
因?yàn)锳WK也是一個解釋器幅聘,就像shell一樣,你可以節(jié)省一個步驟窃植,在文件的開頭添加一行代碼帝蒿,使文件可執(zhí)行:
#!/bin/awk -f
BEGIN { print "File\tOwner" }
{ print $8, "\t", $3}
END { print " - DONE -" }
然后執(zhí)行“chmod +x”并將此文件作為一個新的UNIX命令進(jìn)行ise。
注意“#!/bin/awk”后面的“-f”選項(xiàng)巷怜,它也用于第三種格式葛超,在這種格式中,您使用AWK直接執(zhí)行文件延塑,即“awk - f文件名”绣张。“-f”選項(xiàng)指定包含指令的AWK文件页畦。如您所見胖替,AWK將以“#”開頭的行視為注釋,就像shell一樣豫缨。準(zhǔn)確地說独令,從“#”到行尾的任何內(nèi)容都是注釋(除非它在AWK字符串中)。但是好芭,我總是在行首用“#”來注釋AWK腳本燃箭,原因我將在后面討論。
應(yīng)該使用哪種格式?如果可能的話舍败,我更喜歡最后一種格式招狸。它更短更簡單。調(diào)試問題也更容易邻薯。如果您需要使用shell裙戏,并且希望避免使用太多的文件,您可以像我們在第一個和第二個示例中所做的那樣組合它們厕诡。
用哪種shell搭配AWK?
原始AWK的格式不是自由格式的累榜。你不能把換行符放在任何地方。他們必須去特定的地方灵嫌。確切地說壹罚,在最初的AWK中,您可以在大括號后面和命令末尾插入一個新行字符寿羞,但不能在其他地方插入猖凛。如果你想在任何地方把一條長線分成兩行,你必須使用反斜杠(awk_example2.awk):
#!/bin/awk -f
BEGIN { print "File\tOwner" }
{ print $8, "\t", \
$3}
END { print " - DONE -" }
Bourne shell版本是( awk_example2.sh):
#!/bin/sh
awk '
BEGIN { print "File\tOwner" }
{ print $8, "\t", \
$3}
END { print "done"}
'
C shell版本是( awk_example2.csh):
#!/bin/csh -f
awk '
BEGIN { print "File\tOwner" }\
{ print $8, "\t", \\
$3}\
END { print "done"}\
'
正如您所看到的绪穆,這演示了C shell在封裝AWK腳本時是多么笨拙辨泳。不僅每一行都需要反斜杠虱岂,有些行需要兩個斜杠,然后使用原來的AWK漠吻。更新的AWK更靈活量瓜,可以添加新行。
很多人途乃,像我一樣,會警告你注意C shell扔傅。有些問題很微妙耍共,你可能永遠(yuǎn)也看不到。嘗試在C shell腳本中包含AWK或sed腳本猎塞,而反斜杠會讓您發(fā)瘋试读。這就是多年前說服我學(xué)習(xí)Bourne shell的原因,當(dāng)時我剛開始學(xué)習(xí)(在Korn shell或Bash shell可用之前)荠耽。即使您堅(jiān)持使用C shell钩骇,至少也應(yīng)該學(xué)習(xí)足夠多的Borne/POSIX shell來設(shè)置變量,由于某種奇怪的巧合铝量,這將是下一節(jié)的主題倘屹。
動態(tài)變量
因?yàn)槟梢酝ㄟ^把"#!/bin/awk -f"寫在第一行中使腳本可執(zhí)行,所以不需要在shell腳本中包含AWK腳本慢叨,除非您希望消除對額外文件的需要纽匙,或者希望將變量傳遞到AWK腳本的內(nèi)部。由于這是一個常見的問題拍谐,現(xiàn)在正是解釋該技術(shù)的好時機(jī)烛缔。我將通過顯示一個只打印一列的簡單AWK程序來實(shí)現(xiàn)這一點(diǎn)。注意:第一個版本會有一個bug轩拨。 列的數(shù)目將由第一個參數(shù)指定践瓷。程序的第一個版本的名字我們稱之為“列”,看起來是這樣的:
#!/bin/sh
#NOTE - this script does not work!
column=$1
awk '{print $column}'
建議的用法是:
ls -l | Column 3
未完待續(xù)...