您的位置:首页 > 其它

『zz』awk学习小结

2011-08-16 10:53 197 查看
wk:好用的資料處理工具

awk 也是一個非常棒的資料處理工具!相較於 sed 常常作用於一整個行的處理, awk 則比較傾向於一行當中分成數個『欄位』來處理。因此,awk 相當的適合處理小型的數據資料處理呢!awk 通常運作的模式是這樣的:

[root@www ~]# awk '條件類型1{動作1} 條件類型2{動作2} ...' filename

awk 後面接兩個單引號並加上大括號 {} 來設定想要對資料進行的處理動作。 awk 可以處理後續接的檔案,也可以讀取來自前個指令的 standard output 。 但如前面說的, awk 主要是處理『每一行的欄位內的資料』,而預設的『欄位的分隔符號為 "空白鍵" 或 "[tab]鍵" 』!舉例來說,我們用
last 可以將登入者的資料取出來,結果如下所示:

[root@www ~]# last -n 5 <==僅取出前五行
root     pts/1   192.168.1.100  Tue Feb 10 11:21   still logged in
root     pts/1   192.168.1.100  Tue Feb 10 00:46 - 02:28  (01:41)
root     pts/1   192.168.1.100  Mon Feb  9 11:41 - 18:30  (06:48)
dmtsai   pts/1   192.168.1.100  Mon Feb  9 11:41 - 11:41  (00:00)
root     tty1                   Fri Sep  5 14:09 - 14:10  (00:01)

若我想要取出帳號與登入者的 IP ,且帳號與 IP 之間以 [tab] 隔開,則會變成這樣:

[root@www ~]# last -n 5 | awk '{print $1 "\t" $3}'
root    192.168.1.100
root    192.168.1.100
root    192.168.1.100
dmtsai  192.168.1.100
root    Fri

上表是 awk 最常使用的動作!透過 print 的功能將欄位資料列出來!欄位的分隔則以空白鍵或 [tab] 按鍵來隔開。 因為不論哪一行我都要處理,因此,就不需要有 "條件類型" 的限制!我所想要的是第一欄以及第三欄, 但是,第五行的內容怪怪的~這是因為資料格式的問題啊!所以囉~使用 awk 的時候,請先確認一下你的資料當中,如果是連續性的資料,請不要有空格或 [tab] 在內,否則,就會像這個例子這樣,會發生誤判喔!

另外,由上面這個例子你也會知道,在每一行的每個欄位都是有變數名稱的,那就是 $1, $2... 等變數名稱。以上面的例子來說, root 是 $1 ,因為他是第一欄嘛!至於 192.168.1.100 是第三欄, 所以他就是 $3 啦!後面以此類推~呵呵!還有個變數喔!那就是 $0 ,$0
代表『一整列資料』的意思~以上面的例子來說,第一行的 $0 代表的就是『root .... 』那一行啊! 由此可知,剛剛上面五行當中,整個 awk 的處理流程是:

讀入第一行,並將第一行的資料填入 $0, $1, $2.... 等變數當中;
依據 "條件類型" 的限制,判斷是否需要進行後面的 "動作";
做完所有的動作與條件類型;
若還有後續的『行』的資料,則重複上面 1~3 的步驟,直到所有的資料都讀完為止。

經過這樣的步驟,你會曉得, awk 是『以行為一次處理的單位』, 而『以欄位為最小的處理單位』。好了,那麼
awk 怎麼知道我到底這個資料有幾行?有幾欄呢?這就需要 awk 的內建變數的幫忙啦~

變數名稱代表意義
NF每一行 ($0) 擁有的欄位總數
NR目前 awk 所處理的是『第幾行』資料
FS目前的分隔字元,預設是空白鍵
我們繼續以上面 last -n 5 的例子來做說明,如果我想要:

列出每一行的帳號(就是 $1);
列出目前處理的行數(就是 awk 內的 NR 變數)
並且說明,該行有多少欄位(就是 awk 內的 NF 變數)

則可以這樣:

Tips:

要注意喔,awk 後續的所有動作是以單引號『 ' 』括住的,由於單引號與雙引號都必須是成對的, 所以, awk 的格式內容如果想要以 print 列印時,記得非變數的文字部分,包含上一小節 printf 提到的格式中,都需要使用雙引號來定義出來喔!因為單引號已經是
awk 的指令固定用法了!
[root@www ~]# last -n 5| awk '{print $1 "\t lines: " NR "\t columns: " NF}'
root     lines: 1        columns: 10
root     lines: 2        columns: 10
root     lines: 3        columns: 10
dmtsai   lines: 4        columns: 10
root     lines: 5        columns: 9
# 注意喔,在 awk 內的 NR, NF 等變數要用大寫,且不需要有錢字號 $ 啦!

這樣可以瞭解 NR 與 NF 的差別了吧?好了,底下來談一談所謂的 "條件類型" 了吧!

awk 的邏輯運算字元

既然有需要用到 "條件" 的類別,自然就需要一些邏輯運算囉~例如底下這些:

運算單元代表意義
>大於
<小於
>=大於或等於
<=小於或等於
==等於
!=不等於
值得注意的是那個『 == 』的符號,因為:

邏輯運算上面亦即所謂的大於、小於、等於等判斷式上面,習慣上是以『 == 』來表示;
如果是直接給予一個值,例如變數設定時,就直接使用 = 而已。

好了,我們實際來運用一下邏輯判斷吧!舉例來說,在 /etc/passwd 當中是以冒號 ":" 來作為欄位的分隔, 該檔案中第一欄位為帳號,第三欄位則是 UID。那假設我要查閱,第三欄小於 10 以下的數據,並且僅列出帳號與第三欄, 那麼可以這樣做:

[root@www ~]# cat /etc/passwd | \
> awk '{FS=":"} $3 < 10 {print $1 "\t " $3}'
root:x:0:0:root:/root:/bin/bash
bin      1
daemon   2
....(以下省略)....

有趣吧!不過,怎麼第一行沒有正確的顯示出來呢?這是因為我們讀入第一行的時候,那些變數 $1, $2... 預設還是以空白鍵為分隔的,所以雖然我們定義了 FS=":" 了, 但是卻僅能在第二行後才開始生效。那麼怎麼辦呢?我們可以預先設定 awk 的變數啊! 利用 BEGIN 這個關鍵字喔!這樣做:

[root@www ~]# cat /etc/passwd | \
> awk 'BEGIN {FS=":"} $3 < 10 {print $1 "\t " $3}'
root     0
bin      1
daemon   2
......(以下省略)......

很有趣吧!而除了 BEGIN 之外,我們還有 END 呢!另外,如果要用 awk 來進行『計算功能』呢?以底下的例子來看, 假設我有一個薪資資料表檔名為 pay.txt ,內容是這樣的:

Name    1st     2nd     3th
VBird   23000   24000   25000
DMTsai  21000   20000   23000
Bird2   43000   42000   41000

如何幫我計算每個人的總額呢?而且我還想要格式化輸出喔!我們可以這樣考慮:

第一行只是說明,所以第一行不要進行加總 (NR==1 時處理);
第二行以後就會有加總的情況出現 (NR>=2 以後處理)

[root@www ~]# cat pay.txt | \
> awk 'NR==1{printf "%10s %10s %10s %10s %10s\n",$1,$2,$3,$4,"Total" }
NR>=2{total = $2 + $3 + $4
printf "%10s %10d %10d %10d %10.2f\n", $1, $2, $3, $4, total}'
Name        1st        2nd        3th      Total
VBird      23000      24000      25000   72000.00
DMTsai      21000      20000      23000   64000.00
Bird2      43000      42000      41000  126000.00

上面的例子有幾個重要事項應該要先說明的:

awk 的指令間隔:所有 awk 的動作,亦即在 {} 內的動作,如果有需要多個指令輔助時,可利用分號『;』間隔, 或者直接以 [Enter] 按鍵來隔開每個指令,例如上面的範例中,鳥哥共按了三次 [enter] 喔!
邏輯運算當中,如果是『等於』的情況,則務必使用兩個等號『==』!
格式化輸出時,在 printf 的格式設定當中,務必加上 \n ,才能進行分行!
與 bash shell 的變數不同,在 awk 當中,變數可以直接使用,不需加上 $ 符號。

利用 awk 這個玩意兒,就可以幫我們處理很多日常工作了呢!真是好用的很~ 此外, awk 的輸出格式當中,常常會以 printf 來輔助,所以, 最好你對 printf 也稍微熟悉一下比較好啦!另外, awk 的動作內 {} 也是支援 if (條件) 的喔! 舉例來說,上面的指令可以修訂成為這樣:

[root@www ~]# cat pay.txt | \
> awk '{if(NR==1) printf "%10s %10s %10s %10s %10s\n",$1,$2,$3,$4,"Total"}
NR>=2{total = $2 + $3 + $4
printf "%10s %10d %10d %10d %10.2f\n", $1, $2, $3, $4, total}'

你可以仔細的比對一下上面兩個輸入有啥不同~從中去瞭解兩種語法吧!我個人是比較傾向於使用第一種語法, 因為會比較有統一性啊! ^_^

除此之外, awk 還可以幫我們進行迴圈計算喔!真是相當的好用!不過,那屬於比較進階的單獨課程了, 我們這裡就不再多加介紹。如果你有興趣的話,請務必參考延伸閱讀中的相關連結喔 (註4)。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: