AWK的基本格式:
awk [options] 'program' file… 注釋: program->pattern{action statements;..} pattern和action: ?pattern部分決定動作語句何時觸發及觸發事件 (BEGIN,END) ?action statements對數據進行處理,放在{}內指明 (print, printf)
awk工作原理:
第一步:執行BEGIN{action;… }語句塊中的語句
第二步:從文件或標準輸入(stdin)讀取一行,然后執行pattern{ action;… }語句塊,它逐行掃描文件,從第一行到最后一行重復這個過程,直到文件全部被讀取完畢。
第三步:當讀至輸入流末尾時,執行END{action;…}語句塊
注意:pattern語句塊中的通用命令是最重要的部分,也是可選的。如果沒有提供pattern語句塊,則默認執行{ print },即打印每一個讀取到的行,awk讀取的每一行都會執行該語句塊
awk [options] 'program' file… program->pattern{action statements;..} pattern和action: ?pattern部分決定動作語句何時觸發及觸發事件 (BEGIN,END) ?action statements對數據進行處理,放在{}內指明 (print, printf) 注意:awk程序通常由:BEGIN語句塊、能夠使用模式匹配的通用語句塊、END語句塊,共3部分組成。BEGIN語句塊和END語句塊分別為文家處理前和處理后執行的語句段
1)OPTIONS
選項(options):
-F指明輸入時用到的字段分隔符(默認以空格為分隔符)
-v var內置變量|var=value: 自定義變量
變量分為內置變量和自定義變量:
●內置變量:
FS:輸入字段分隔符,默認為空白字符(與-F效果相同)
[root@dashui ~]# awk -v FS=":" '{print $1,$3}' /etc/passwd root 0 bin 1 daemon 2
OFS:輸出字段分隔符,默認為空白字符
[root@dashui ~]# awk -v FS=":" -v OFS="*" '{print $1,$3}' /etc/passwd root*0 bin*1 daemon*2
RS:輸入記錄分隔符,指定讀入時的換行符,原換行符仍有效
[root@dashui ~]# awk -v RS=' ' '{print}' hah //指定讀入時的分割符,只要出現空格就被換行 nihao a haha i amfanin [root@dashui ~]# cat hah nihao a haha i amfanin
ORS:輸出記錄分隔符,輸出時用指定符號代替換行符
[root@dashui ~]# cat hah nihao a haha i amfanin [root@dashui ~]# awk -v ORS='=== ' '{print}' hah //指定輸出分隔符為===,所以原來換行被替換成=== nihao a haha=== i amfanin=== [root@dashui ~]#
NF:字段數量
[root@dashui ~]# awk -F: '{print NF}' /etc/passwd //以:為分隔符,每一行有幾個字段 7 7 7
NR:行號(如果有多個文件,則行號統計在一起)
[root@dashui ~]# awk '{print NR}' hah 1 2 [root@dashui ~]# awk '{print NR}' hah /etc/fstab //hah的行號和/etc/fstab的統計在了一塊 1 2 3 4 5 6 7 8 9 10 11 12 13 14
FNR:各文件分別計數,行號
[root@dashui ~]# awk '{print FNR}' hah /etc/fstab 1 2 1 2 3 4 5 6 7 8 9 10 11 12
FILENAME:當前文件名
[root@dashui ~]# awk '{print FILENAME}' hah //因為前面的pattern沒有寫,所以默認每讀入一行,就執行一次print hah hah [root@dashui ~]# cat hah nihao a haha i amfanin
ARGC:命令行參數的個數
[root@dashui ~]# awk '{print ARGC}' hah //其中第一個參數為awk ,第二個為 hah 2 2
ARGV:數組,保存的是命令行所給定的各參數
[root@dashui ~]# awk '{print ARGV[0]}' hah //0是第一個參數,1是第二個參數 awk awk [root@dashui ~]# awk '{print ARGV[1]}' hah hah hah
●自定義變量
(1) -v var=value
變量名區分字符大小寫
(2) 在program中直接定義
[root@dashui ~]# awk -v name=xiaoshui 'BEGIN{print name}' xiaoshui [root@dashui ~]# awk 'BEGIN{name="xiaozhao";print name}' xiaozhao
注意:自定義變量時需要加上雙引號,不加的話可能會定義不成功,如下
[root@dashui ~]# awk 'BEGIN{name=xiaozhao;print name}' [root@dashui ~]# awk 'BEGIN{name="xiaozhao";print name}' xiaozhao
2)program
program分為pattern和action
?pattern部分決定動作語句何時觸發及觸發事件 (BEGIN,END) ?action statements對數據進行處理,放在{}內指明 (print, printf)
(1)action(print、printf)
?Expressions:算術,比較表達式等
?Control statements:if, while等
?Compound statements:組合語句
?input statements
?output statements:print等
print格式:print item1, item2, …
?(1) 逗號分隔符
?(2) 輸出的各item可以字符串,也可以是數值;當前記錄的字段、變量或awk的表達式
?(3) 如省略item,相當于print $0
[root@dashui ~]# awk -F : '{print $1,$3}' /etc/passwd root 0 bin 1 daemon 2 [root@dashui ~]# awk -F : '{print $1,"xiaoshui",$3}' /etc/passwd root xiaoshui 0 bin xiaoshui 1 daemon xiaoshui 2 [root@dashui ~]# awk -F : '{print }' /etc/passwd root:x:0:0:root:/root:/bin/bash bin:x:1:1:bin:/bin:/sbin/nologin daemon:x:2:2:daemon:/sbin:/sbin/nologin
printf
格式化輸出:printf“FORMAT”, item1, item2, …
(1) 必須指定FORMAT
(2) 不會自動換行,需要顯式給出換行控制符,\n
(3) FORMAT中需要分別為后面每個item指定格式符
格式符:與item一一對應
%c: 顯示字符的ASCII碼
%d, %i: 顯示十進制整數
%e, %E:顯示科學計數法數值
%f:顯示為浮點數
%g, %G:以科學計數法或浮點形式顯示數值
%s:顯示字符串
%u:無符號整數
%%: 顯示%自身
修飾符:
#[.#]:第一個數字控制顯示的寬度;第二個#表示小數點后精度,%3.1f
-: 左對齊(默認右對齊)%-15s
+:顯示數值的正負符號%+d
[root@dashui ~]# awk -F : '{printf "%s %d\n",$1,$3 }' /etc/passwd //如果不加\n默認是不換行的 root 0 bin 1 daemon 2
(2)pattern
PATTERN:根據pattern條件,過濾匹配的行,再做處理
(1)如果未指定:空模式,匹配每一行
(2) /regular expression/:僅處理能夠模式匹配到的行,需要用/ /括起來
[root@dashui ~]# awk '/^UUID/{print $1}' /etc/fstab // 以UUID開頭的行 UUID=136f7cbb-d8f6-439b-aa73-3958bd33b05f UUID=bf3d4b2f-4629-4fd7-8d70-a21302111564 UUID=cbf33183-93bf-4b4f-81c0-ea6ae91cd4f6 UUID=5e11b173-f7e2-4994-95b9-55cc4c41f20b
(3) relational expression: 關系表達式,結果有“真”有“假”,結果為“真”才會被處理
真:結果為非0值,非空字符串
假:結果為空字符串或0值
[root@dashui ~]# awk '0{print $0}' hah //因為前面為0,所以不執行 [root@dashui ~]# awk '!0{print $0}' hah //與上面相反 nihao a haha i amfanin [root@dashui ~]# awk -F: '$3==0{print $0}' /etc/passwd //只有當$3=0時候,才會執行print root:x:0:0:root:/root:/bin/bash
(4) line ranges:行范圍
startline,endline:/pat1/,/pat2/不支持直接給出數字格式
[root@dashui ~]# awk -F: '/^root\>/,/^daemon\>/{print}' /etc/passwd //打印以root開頭與以daemon開頭的之間的行 root:x:0:0:root:/root:/bin/bash bin:x:1:1:bin:/bin:/sbin/nologin daemon:x:2:2:daemon:/sbin:/sbin/nologin [root@dashui ~]#
(5)(5) BEGIN/END模式
BEGIN{}: 僅在開始處理文件中的文本之前執行一次
END{}:僅在文本處理完成之后執行一次
[root@dashui ~]# awk 'BEGIN{print "start"}{print $0}END{print "end"}' hah //在開始和結束時候分別打印start和end start nihao a haha i amfanin end [root@dashui ~]# cat hah nihao a haha i amfanin
AWK的操作符
算術操作符:
x+y, x-y, x*y, x/y, x^y, x%y
-x: 轉換為負數
+x: 轉換為數值
[root@dashui ~]# awk 'BEGIN{i=1;j=2;sum=i+j;{print sum}}' 3
字符串操作符:沒有符號的操作符,字符串連接
賦值操作符:
=, +=, -=, *=, /=, %=, ^=
++, —
比較操作符:
>, >=, <, <=, !=, ==
模式匹配符:
~:左邊是否和右邊匹配包含
!~:是否不匹配
[root@dashui ~]# awk -F: '$1~"root"{print $0}' /etc/passwd //當$1即usrename為root或者包含 root時候,執行print root:x:0:0:root:/root:/bin/bash chroot:x:1003:1003:,62984566:/home/chroot:/bin/bash rooter:x:3320:4327:,62984566:/home/rooter:/bin/bash [root@dashui ~]# awk -F: '$3<2{print $0}' /etc/passwd //$3即uid小于2時,執行print root:x:0:0:root:/root:/bin/bash bin:x:1:1:bin:/bin:/sbin/nologin
邏輯操作符:與&&,或||,非!
[root@dashui ~]# awk -F: '$3>1000 && $3<2000{print $0}' /etc/passwd xiaoshui:x:1001:1001:xiaoshui,342342342:/home/xiaoshui:/bin/bash chroot:x:1003:1003:,62984566:/home/chroot:/bin/bash centos:x:1004:1004:,62984566:/home/centos:/bin/bash [root@dashui ~]# awk -F: '$1=="root" || $1=="xiaoshui"{print $0}' /etc/passwd root:x:0:0:root:/root:/bin/bash xiaoshui:x:1001:1001:xiaoshui,342342342:/home/xiaoshui:/bin/bash
awk控制語句
●{ statements;… } 組合語句
●if(condition) {statements;…}
●if(condition) {statements;…} else {statements;…}
●while(conditon) {statments;…}
●do {statements;…} while(condition)
●for(expr1;expr2;expr3) {statements;…}
●break
●continue
●delete array[index]
●delete array
●exit
(1){ statements;… } 組合語句
[root@dashui ~]# awk '{a=1;print a}' hah //將多個語句組合在一起 1 1
(2)●if(condition) {statements;…}
[root@dashui ~]# awk -F: '{if($3==0){print $0}}' /etc/passwd root:x:0:0:root:/root:/bin/bash
注意:條件在小括號中,條件后的語句需在{ }中
(3)●if(condition) {statements;…} else {statements;…}
● if(condition1){statement1}else if(condition2){statement2}else{statement3}
[root@dashui ~]# awk '{if($0=="dashui"){print "dashui"} else{print "not dashui"}}' hah not dashui not dashui dashui [root@dashui ~]# cat hah nihao a haha i amfanin dashui
(4)●while(conditon) {statments;…}
//下面是找到以空格開頭后跟linux16的行,將匹配到的行中的每個字段的長度與8比較,大于8的輸出 [root@dashui ~]# awk '/^[[:space:]]+linux16/{i=1;while(i<=NF){if(length($i)>8){print $i,length($i)};i++}}' /etc/grub2.cfg /vmlinuz-3.10.0-327.el7.x86_64 30 root=UUID=136f7cbb-d8f6-439b-aa73-3958bd33b05f 46 net.ifnames=0 13 /vmlinuz-0-rescue-3f3be6c44d1047a8b32f91efd2f2c5ab 50 root=UUID=136f7cbb-d8f6-439b-aa73-3958bd33b05f 46 net.ifnames=0 13
做上面的實驗時,因為手抖輸出了點,將if后面的print中i前面的$符號給忘記了,結果就成了下面的情況
[root@dashui ~]# awk '/^[[:space:]]+linux16/{i=1;while(i<=NF){if(length($i)>8){print i,length(i)};i++}}' /etc/grub2.cfg 2 1 3 1 7 1 2 1 3 1 7 1 //分析:print i,因為前面i賦值的是數字,本意是想打印$i,即各個字段,當$符號丟掉時,i也只是代表數字了 所以打印出來的237237表示的就是第幾個字段,而length(i)就更好理解了,因為length()就是求括號中的 字符串的長度,且因為i都為個位數,所以就為1嘍(注意:如果單單是length(i),i之前沒有被定義,此時打印出來 的為0,以為i之前沒有被定義,所以為空)
(5)do-while循環
語法:do {statement;…}while(condition)
意義:無論真假,至少執行一次循環體
[root@dashui ~]# awk 'BEGIN{i=0;do{i++}while(i<1){print i}}' 1 [root@dashui ~]# awk 'BEGIN{i=0;do{i++}while(i<=1){print i}}' 2
(6)for循環
語法:for(expr1;expr2;expr3) {statement;…}
[root@dashui ~]# awk '/^[[:space:]]+linux16/{for(i=1;i<NF;i++){print $i}}' /etc/grub2.cfg linux16 /vmlinuz-3.10.0-327.el7.x86_64 root=UUID=136f7cbb-d8f6-439b-aa73-3958bd33b05f ro rhgb quiet linux16 /vmlinuz-0-rescue-3f3be6c44d1047a8b32f91efd2f2c5ab root=UUID=136f7cbb-d8f6-439b-aa73-3958bd33b05f ro rhgb quiet
特殊用法:能夠遍歷數組中的元素;
語法:for(varin array) {for-body}
[root@dashui ~]# awk -F: '{bash[$7]++}END{for (i in bash){print i,bash[i]}}' /etc/passwd /etc/nologin 2 /bin/sync 1 /bin/bash 47 /shell/csh 1 /sbin/nologin 34 /sbin/halt 1 /bin/csh 2 /sbin/shutdown 1 [root@dashui ~]#
(7)switch語句
語法:switch(expression) {case VALUE1 or /REGEXP/: statement; case VALUE2 or /REGEXP2/: statement; …; default: statement}
(8)break和continue
break表示跳出循環,而continue表示跳過本輪循環
[root@dashui ~]# awk 'BEGIN{sum=0;for(i=1;i<10;i++){if(i==5){break}print i}}' 1 2 3 4 [root@dashui ~]# awk 'BEGIN{sum=0;for(i=1;i<10;i++){if(i==5){continue}print i}}' 1 2 3 4 6 7 8 9
(9)next
提前結束對本行處理而直接進入下一行處理(awk自身循環)
#$3%2!=0即uid為奇數,跳過此行,即只打印uid為偶束的行 [root@dashui ~]# awk -F: '{if($3%2!=0) next; print $1,$3}' /etc/passwd root 0 daemon 2 lp 4 shutdown 6 mail 8 games 12
awk數組
關聯數組:array[index-expression]
index-expression:
?(1) 可使用任意字符串;字符串要使用雙引號括起來
?(2) 如果某數組元素事先不存在,在引用時,awk會自動創建此元素,并將其值初始化為“空串”
?若要判斷數組中是否存在某元素,要使用“index in array”格式進行遍歷
#注意:如果數組的鍵值為字符串時,最后以雙引號給引起來 [root@dashui ~]# awk 'BEGIN{weekdays["mon"]="Monday";weekdays["tue"]="Tuesday";print weekdays["mon"]}' Monday
若要遍歷數組中的每個元素,要使用for循環
[root@dashui ~]# netstat -tan|awk '/^tcp\>/{state[$NF]++}END{for(i in state){print i,state[i]}}' LISTEN 3 ESTABLISHED 1
awk函數
●數值處理:
rand():返回0和1之間一個隨機數
#注意:需配合srand()函數使用,不然不是隨機數 [root@dashui ~]# awk 'BEGIN{srand(); for (i=1;i<=10;i++)print int(rand()*100)}' 54 45 23 24 14 72 56 92 31 31
●字符串處理:
?length([s]):返回指定字符串的長度
?sub(r,s,[t]):對t字符串進行搜索r表示的模式匹配的內容,并將第一個匹配的內容替換為s
?gsub(r,s,[t]):對t字符串進行搜索r表示的模式匹配的內容,并全部替換為s所表示的內容
[root@dashui ~]# echo "2008:08:08 08:08:08"|awk 'sub(":","-",$0)' 2008-08:08 08:08:08 [root@dashui ~]# echo "2008:08:08 08:08:08"|awk 'gsub(":","-",$0)' 2008-08-08 08-08-08 [root@dashui ~]#
?split(s,array,[r]):以r為分隔符,切割字符s,并將切割后的結果保存至array所表示的數組中,第一個索引值為1,第二個索引值為2,…
#這里使用split函數將第五個字段中的ip和端口號分開,只取出了ip。 [root@dashui ~]# netstat -tan | awk '/^tcp\>/{split($5,ip,":");count[ip[1]]++}END{for (i in count) {print i,count[i]}}' 10.1.0.82 1 0.0.0.0 3 [root@dashui ~]# netstat -tan Active Internet connections (servers and established) Proto Recv-Q Send-Q Local Address Foreign Address State tcp 0 0 0.0.0.0:22 0.0.0.0:* LISTEN tcp 0 0 127.0.0.1:631 0.0.0.0:* LISTEN tcp 0 0 127.0.0.1:25 0.0.0.0:* LISTEN tcp 0 52 10.1.0.26:22 10.1.0.82:54143 ESTABLISHED tcp6 0 0 :::22 :::* LISTEN tcp6 0 0 ::1:631 :::* LISTEN tcp6 0 0 ::1:25 :::* LISTEN [root@dashui ~]#
?自定義函數
格式:
function name ( parameter, parameter, … ) {
statements
return expression
}
#這里自定義了一個函數,求出兩個變量的最大值。 [root@dashui ~]# awk -f awk.fun 3 [root@dashui ~]# cat awk.fun function max(v1,v2) { v1>v2?var=v1:var=v2 return var } BEGIN{a=3;b=2;print max(a,b)}
注意:和之前的shell中的函數有些不同,這里如果需要像awk函數中傳遞變量,則需要在括號中定義形參。
awk中調用shell命令
system命令
[root@dashui ~]# awk BEGIN'{system("hostname")}' dashui.localdomain
空格是awk中的字符串連接符,如果system中需要使用awk中的變量可以使用空格分隔,或者說除了awk的變量外其他一律用""引用起來。
[root@dashui ~]# awk 'BEGIN{name="xiaoshui";system("echo your name is " name)}' your name is xiaoshui
awk腳本
將awk程序寫成腳本,直接調用或執行
#將action寫入到腳本中,然后調用執行 [root@dashui ~]# awk -F: -f f1.awk /etc/passwd root 0 bin 1 daemon 2 adm 3 hu [root@dashui ~]# cat f1.awk {if($3<4)print $1,$3} # 腳本文件中的/bin/awk -f表示是用awk -f來執行下面語句 [root@dashui ~]# ./f1.awk -F: /etc/passwd root 0 bin 1 daemon 2 adm 3 hu [root@dashui ~]# cat f1.awk #!/bin/awk -f #this is a awk script {if($3<4)print $1,$3}
向awk腳本傳遞參數
格式:
awkfile var=value var2=value2… Inputfile
# min和max分別對應腳本文件中的min和max [root@dashui ~]# ./f1.awk -F: min=100 max=200 /etc/passwd avahi-autoipd 170 abrt 173 rtkit 172 usbmuxd 113 pulse 171 [root@dashui ~]# cat f1.awk #!/bin/awk -f {if($3>=min && $3<=max)print $1,$3}
強化練習
1.打印一個表頭,并且打印用戶名和ID
[root@dashui ~]# awk -F: 'BEGIN{printf "Username UID\n"}{printf "%-20s %d\n",$1,$3}' /etc/passwd Username UID root 0 bin 1 daemon 2 adm 3 lp 4 sync 5 shutdown 6 halt 7 mail 8 operator 11 games 12
2.打印一個表頭和表尾,并打印用戶名,ID,及shell
[root@dashui ~]# awk -F: 'BEGIN{printf "Username UID Shell\n"}{printf "%-20s %d %10s\n",$1,$3,$5}END{print "Finished..."}' /etc/passwd Username UID Shell root 0 root bin 1 bin daemon 2 daemon adm 3 adm lp 4 lp sync 5 sync shutdown 6 shutdown ...省略... haha 4376 xixi 4377 hehe 4378 Finished... [root@dashui ~]#
3.對文本中的字段進行字符個數統計
[root@dashui ~]# awk '{print $0,length($0)}' hah nihao a haha 12 i amfanin 9 dashui 6
4.打印字符個數大于等于8的字段
#其實就是比題3多了一條if判斷語句 [root@dashui ~]# awk '{if(length($0)>8){print $0,length($0)}}' hah nihao a haha 12 i amfanin 9
5.統計系統中shell的類型,并打印shell引用的次數
#中間運用了數組和for循環 [root@dashui ~]# awk -F: '{count[$7]++}END{for (i in count){print i,count[i]}}' /etc/passwd /etc/nologin 2 /bin/sync 1 /bin/bash 47 /shell/csh 1 /sbin/nologin 34 /sbin/halt 1 /bin/csh 2 /sbin/shutdown 1
6.統計fstab文件中,各文件系統被引用的次數
#比上題多了一步地址定界 [root@dashui ~]# awk '/^[^#]/{count[$3]++}END{for (i in count){print i,count[i]}}' /etc/fstab swap 1 xfs 3
7.統計系統中各TCP連接狀態的數量
[root@dashui ~]# netstat -tan|awk '/^tcp\>/{state[$6]++}END{for (i in state){print i,state[i]}}' LISTEN 3 ESTABLISHED 1
8.將文本的重復行去掉
#第一次讀取aaa,arr[aaa]因為沒有定義,所以為空,又取非,所以為真,arr[aaa]++是先賦值后加加,所以第一次打印出來 #第二次,在遇見aaa時候,因為之前有值了arr[aaa]=1,所以取反為0,不執行后的print操作,但是++依然正常運行 [root@dashui ~]# awk '!arr[$0]++' hah aaa bbb ccc ddd fff [root@dashui ~]# cat hah aaa bbb ccc aaa ddd aaa aaa fff ccc [root@dashui ~]#
謝謝瀏覽,以后會不定時更新…
原創文章,作者:我的滑板鞋,如若轉載,請注明出處:http://www.www58058.com/48383
寫的很詳細,每一個選項,甚至是變量都有相應的示例,可以看出作者用心哦。