awk
是個很強大的工具, 透過其特製的語法可以在很多變化上處理pipe或檔案內容;之前一段時間不碰後,又忘了之前使用過awk
語法,趁最近又開始接觸來重新複習這個工具。
測試用檔案 – log.txt
假設一個log檔的檔名為log.txt
,且內容如下:
2 this is a test
3 Are you like awk
This's a test
10 There are orange,apple,mongo
基本搭配print做格式化輸出
NOTE:
- 值得注意的是,
$0
在awk
中代表的是整行文字
# 在print使用逗號,可以在輸出時用空白隔開$1與$4
awk '{print $1,$4}' log.txt
(上述指令針對每一行的log,截取第1個與第4個讀取到的文字)
2 a
3 like
This's
10 orange,apple,mongo
透過-F
更改分割字元
由於預設awk
是使用空白當分割字元來處理同一行文字的,若要改變分割字元,則可以使用-F
這個flag。
aws -F , '{print $1,$2}' log.txt
(上述指令針對每一行的log,透過,
分隔以後,截取分割後的第1個與第2個讀取到的文字)
2 a
3 like
This's
10 orange apple
(以這個log檔來看,只有最後一行才會被分割成多個arguments)
透過-v
來代入自訂的變數
透過預先定義好的變數
awk -v a=1 -v b=2 '{print $1,$1+a,b}' log.txt
(上述指令定義了a
, b
2個變數與值,且在print
時使用它們)
2 3 2
3 4 2
This's 1 2
10 11 2
透過運算符號來使用awk
支援的運算符號可以參考這裡
對每一行文字,過濾只有第一個參數大於2
awk '$1>2' log.txt
# output
3 Are you like awk
This's a test
10 There are orange,apple,mongo
對每一行文字,過濾只有第一個參數大於2,且第二個參數必須是"Are"
awk '$1>2 && $2=="Are" {print $1,$2,$3}' log.txt
# output
3 Are you
對每一行文字,列出只有字元數大於20的行
awk 'length>20 {print $0}' log.txt
# output
10 There are orange,apple,mongo
搭配Regular expression使用
在awk
中,可以透過運算符號~
與!~
來去搭配正規表示法使用。
對於每一行文字,當第一組參數不是數字時才會被print
出來
awk '$1 !~ /[0-9]/ {print $0}' log.txt
# output
This's a test
對於每一行文字,只有當第一組參數是數字時才會被print
awk '$1 ~ /[0-9]/ {print $0}' log.txt
# output
2 this is a test
3 Are you like awk
10 There are orange,apple,mongo
對於每一行文字,只有符合正規表示法時才會被print
如果只是要對整行文字作匹配的話,則可以直接用這方式
awk '/re/ ' log.txt
#output
3 Are you like awk
10 There are orange,apple,mongo
或加個!
來過濾掉匹配到的每一行文字
awk '!/re/ ' log.txt
#output
2 this is a test
This's a test
搭配awk
的進階使用
awk
常見可以使用的keyword可以參考這裡。
過濾掉第一行的文字(通常可用於csv檔拿掉header)
awk 'NR != 1' log.txt
# output
3 Are you like awk
This's a test
10 There are orange,apple,mongo
(我猜NR
指的應該是Nnumb of Row)
對文字檔的特定參數做數字加總,並且print出來
awk '{sum+=$1} END {print sum}' log.txt
# output
15
(如果每一行的第一個參數是數字的話,就會對它做加總並暫存在sum
這個變數上)
針對文字檔中的每一行,來做分組與處理
假設我們有個文字檔如下,然後我們想要針對每個Category的值串起來在印出來
Category: OS
Windows
Liux
Unix
Category: CPU
x86
arm64
amd64
Category: RAM
1GB
2GB
4GB
8GB
16GB
awk '/Category/ {header=$0; if (v) print v; v=""; next} { v=(!v) ? header"="$0 : v","$0;} END {print v;}' support_sepcs.txt
# output
Category: OS=Windows,Liux,Unix
Category: CPU=x86,arm64,amd64
Category: RAM=1GB,2GB,4GB,8GB,16GB
這個指令用了到幾個進階的功能:
/Category/
用來匹配當遇到Category
那一行的文字時,會在{header=$0 ...;next}
中處理。(結尾的next
是指說跳過後面的{v=(!v)…}
相關的工作)() ? :
用三元運算符號來去給v
這個變數值。END
用來處理最後的收尾。- 整個指令的邏輯是,當如果遇到文字中含
Category
時,則那行的文字會當作是接下去的header
,然後如果v
目前是有值的情況下,則print v
。
(這個情況v
會是前面的字串組成的結果, 例如處理Category: CPU
時,v
這時會有值,且值會是Category: OS=Windows,Liux,Unix
)。
若沒遇到Category
的話,則繼續append
目前的這一行文字到v
這個變數上。
最後一個Category: RAM
則是透過END { print v}
來去print
出來。 - 如果在
header
後想要多處理else
的話,會是這樣的語法:{header=$0; {if (v) { print v; v=""; next } else {v="";next}}
總結
整個awk
的進階使用還更複雜,尤其是它支援許多語法,透過它的語法可以寫成另一個awk
的script了,然後在指令中讀取來使用,像是awk -f cal.awk log.txt
。