awk命令高級應用:數組、函數及控制語句

一、簡介

awk命令作為一種編程語言,其用法也包括了一些高級應用如控制語句、函數及數組等。這些高級應用都讓awk命令更加強大,應用更加廣泛,使得其能滿足更多復雜的需求。

二、awk命令的數組

awk命令也可以結合數組來完成一系列的工作,其數組格式為:array[index-expression],其中index-expression可使用任意字符串,字符串要使用雙引號括起來;如果數組中的元素事先不存在,在引用時,awk命令會自動創建此元素,并將其值初始化為“空串”。

若需要對數組進行判斷是否存在某個元素,可以以index in array格式進行判斷確認,index會遍歷數組array中的索引,如:

[root@localhost tmp]# awk -v i=mon 'BEGIN{weekdays["mon"]="monday";weekdays["tue"]="tuesday";if(i in weekdays) print weekdays[i]}'
monday

三、awk命令的函數

awk命令也支持函數的編寫,通常來說用得較多的為awk命令的幾個內置函數,其分別為:

rand():返回0和1之間一個隨機數,單獨使用rand()函數的話只會隨機生成一次,后續多次執行也是生成同一批次的隨機數;
srand([expr]):使用expr生成隨機數,如果不指定expr,默認使用當前時間生成隨機數;先執行srand(),在執行rand(),能讓刷新rand()輸出的隨機數;
int(expr):將數值取整;
length([s]):返回指定字符串的長度;
sub(r,s,[t]):以r表示的模式來查找t所表示的字符串中匹配的內容,并將其第一次出現的匹配內容替換為s的內容;
gsub(r,s,[t]):以r表示的模式來查找t所表示的字符串中匹配的內容,并將所有的匹配內容替換為s的內容;
split(s,a[,r]):以r為分隔符切割字符串s,并將切割后的結果保存至a所表示的數組中;

awk命令也支持函數的自定義,其格式為:

function function_name(argument1,argument2,...)
{
function_body
}

上述中,function_name為用戶定義的函數的名稱,函數通常可以接受以逗號分割的多個arguments,參數是可選的;通常來說一個function_body是由一個或多個語句組成的。
如下例子,為定義一個函數,打印UID大于100的用戶名及用戶UID:

[root@localhost ~]# awk -F: 'function test(a,b){if(b>100) printf "User:%-20s UID:%-10s\n",a,b};test($1,$3)' /etc/passwd
User:avahi-autoipd        UID:170       
User:systemd-bus-proxy    UID:999       
User:systemd-network      UID:998       
User:polkitd              UID:997       
User:charlie              UID:1000    

四、awk命令的控制語句

簡介中提及awk命令是一種編程語言,那么作為一種編程語言,其也有相應的控制語句。其控制語句的類型與bash shell編程的類似,包括:if-else、while、for、switch、break、continue和next。其中break、continue用于跳出循環及跳出本次循環,next用于提前結束當前行的處理,直接進入下一行。
下面重點介紹下其他的控制語句。

  • if-else
    awk命令的if-else語句通常用于對匹配的行或字段做條件判斷選擇,其格式通常為:

awk [options] '{if (condition) {statements} [else {statements}] }' /PATH/TO/SOMEFILE

如:
判斷用戶的UID,如果小于1000,則輸出說明該用戶為系統用戶,大于或等于1000則輸出說明該用戶為普通用戶:

[root@localhost ~]# awk -F: '{if ( $3<1000 ) { print $1,"is system user."} else {print $1,"is common user."}}' /etc/passwd
root is system user.
bin is system user.
daemon is system user.
adm is system user.
lp is system user.
sync is system user.
shutdown is system user.
halt is system user.
mail is system user.
operator is system user.
games is system user.
ftp is system user.
nobody is system user.
avahi-autoipd is system user.
systemd-bus-proxy is system user.
systemd-network is system user.
dbus is system user.
polkitd is system user.
tss is system user.
postfix is system user.
sshd is system user.
charlie is common user.
  • while循環
    awk命令的while循環常用于對一行內的多個字段進行逐個處理或者對數組中的各元素進行逐一處理。其格式為:

awk '[/PATTERN/]{while(condition) {statements}}' /PATH/TO/SOMEFILE

如:統計字段的長度:

[root@localhost ~]# awk -F: '/bash$/{i=1;while(i<=NF) {printf "%s的字段長度為:%-5s\n",$i,length($i);i++}}' /etc/passwd
root的字段長度為:4    
x的字段長度為:1    
0的字段長度為:1    
0的字段長度為:1    
root的字段長度為:4    
/root的字段長度為:5    
/bin/bash的字段長度為:9    
amandabackup的字段長度為:12   
x的字段長度為:1    
33的字段長度為:2    
6的字段長度為:1    
Amanda user的字段長度為:11   
/var/lib/amanda的字段長度為:15   
/bin/bash的字段長度為:9    
postgres的字段長度為:8    
x的字段長度為:1    
26的字段長度為:2    
26的字段長度為:2    
  • for循環
    awk命令的for 循環常用于進行累加或遍歷操作,如累計某個關鍵字出現次數、遍歷數組等等。其常見的格式為:

awk '/PATTERN/{for(變量賦值;判斷條件;條件變化) {循環體}}' /PATH/TO/SOMEFILE

如打印匹配行的字段長度:

[root@localhost ~]# awk -F: '/^root/{for(i=1;i<=NF;i++) printf "The length of %s is %s\n",$i,length($i)}' /etc/passwd
The length of root is 4
The length of x is 1
The length of 0 is 1
The length of 0 is 1
The length of root is 4
The length of /root is 5
The length of /bin/bash is 9
  • switch語句

awk的switch語句類似于bashshell編程的case語句,可提供多個命令語句,當條件滿足switch切換條件時,即切換運行指定的命令語句。其格式類似如下:

awk [options] '{switch(CONDITION){case [VALUE|/PATTERN/]:statement;case [VALUE|/PATTERN/]:statement;...;default:statement}}'

如下例子,打印行號為6以及5的倍數的行的行號:

[root@localhost ~]# awk -F: '{switch(NR+5){case 6:{print NR;next}; case /[[:digit:]]+0/: {print NR; next} ;default: print "-------------"}}' /etc/passwd 
1
-------------
-------------
-------------
5
-------------
-------------
-------------
-------------
-------------
-------------
-------------
-------------
-------------
15
-------------
-------------

五、使用案例

  • 次數統計
    統計當前系統中以/bin/bash為默認shell的用戶個數:
[root@localhost ~]# awk -F: '{ if ($NF == "/bin/bash") {shell[$NF]++}} END{for(i in shell) {print i,shell[i]}}' /etc/passwd
/bin/bash 14

查看當前監聽的端口統計:

[root@localhost ~]# netstat -tan | awk '/^tcp\>.*LISTEN.*/{split($4,port,"[:]"); count[port[2]]++} END{for (i in count) { printf "Port %s have %s listening link.\n",i,count[i]}}'
Port 53 have 1 listening link.
Port 445 have 1 listening link.
Port 139 have 1 listening link.
Port 631 have 1 listening link.
Port 22 have 1 listening link.
Port 25 have 1 listening link.
  • 查找替換
    將文件中的bash全部替換為大寫的BASH后打印輸出:
[root@localhost ~]# awk -F: '/.*bash$/{gsub(/bash$/,"BASH",$0);print $0}' /etc/passwd
root:x:0:0:root:/root:/bin/BASH
amandabackup:x:33:6:Amanda user:/var/lib/amanda:/bin/BASH
postgres:x:26:26:PostgreSQL Server:/var/lib/pgsql:/bin/BASH
centos:x:1001:1001::/home/centos:/bin/BASH
federo:x:1002:1002::/home/federo:/bin/BASH
counter:x:1003:1004::/home/counter:/bin/BASH
charlie:x:1004:1005::/home/charlie:/bin/BASH
Jone:x:1006:1007::/Jone:/bin/BASH
Williom:x:1200:1005::/home/Williom:/bin/BASH
mageia:x:1100:1100::/home/linux:/bin/BASH
bash:x:2003:2003::/home/bash:/bin/BASH
testbash:x:2004:2004::/home/testbash:/bin/BASH
basher:x:2005:2005::/home/basher:/bin/BASH
hadoop:x:2007:2007::/home/hadoop:/bin/BASH
  • 打印九九乘法表
[root@localhost ~]# awk 'BEGIN{for(n=1;n<=9;n++){for (i=1;i<=n;i++) printf i"x"n"="i*n" ";printf "\n"}}'
1x1=1 
1x2=2 2x2=4 
1x3=3 2x3=6 3x3=9 
1x4=4 2x4=8 3x4=12 4x4=16 
1x5=5 2x5=10 3x5=15 4x5=20 5x5=25 
1x6=6 2x6=12 3x6=18 4x6=24 5x6=30 6x6=36 
1x7=7 2x7=14 3x7=21 4x7=28 5x7=35 6x7=42 7x7=49 
1x8=8 2x8=16 3x8=24 4x8=32 5x8=40 6x8=48 7x8=56 8x8=64 
1x9=9 2x9=18 3x9=27 4x9=36 5x9=45 6x9=54 7x9=63 8x9=72 9x9=81 
  • 隨機數
    生成10個隨機數:
[root@localhost ~]# awk 'BEGIN{srand();for(i=1;i<=10;i++) printf "%5f\n",rand()}' | cut -d. -f2
102331
880760
844083
462001
686521
368991
974802
394346
514236
192557

統計某個網站的訪問流量大小:

[root@localhost ~]# cat /var/log/httpd/access_log | awk '{sum+=$10} END{printf "%fG\n", sum/1024/1024/1024}'
0.000097G
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 230,563評論 6 544
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 99,694評論 3 429
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 178,672評論 0 383
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,965評論 1 318
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 72,690評論 6 413
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 56,019評論 1 329
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 44,013評論 3 449
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 43,188評論 0 290
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 49,718評論 1 336
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 41,438評論 3 360
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,667評論 1 374
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 39,149評論 5 365
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,845評論 3 351
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 35,252評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,590評論 1 295
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 52,384評論 3 400
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,635評論 2 380

推薦閱讀更多精彩內容

  • awk介紹awk變量printf命令:實現格式化輸出操作符awk patternawk actionawk數組aw...
    哈嘍別樣閱讀 1,584評論 0 4
  • awk: grep,sed,awk grep:文本過濾 sed:文本編輯 awk:文本格式化工具; 1 什么是aw...
    木林森閱讀 1,807評論 0 16
  • linux資料總章2.1 1.0寫的不好抱歉 但是2.0已經改了很多 但是錯誤還是無法避免 以后資料會慢慢更新 大...
    數據革命閱讀 12,202評論 2 33
  • 轉載 原文的排版和內容都更加友好,并且詳細,我只是在這里貼出了一部分留作自己以后參考和學習,如希望更詳細了解AWK...
    XKirk閱讀 3,246評論 2 25
  • awk命令的基本使用 [root@shellscript ~]# head -n 3 /etc/passwd | ...
    古寒飛閱讀 1,078評論 0 2