awk是一種編程語言,用於在linux/unix下對文本和數據進行處理。數據可以來自標准輸入(stdin)、一個或多個文件,或其它命令的輸出。它支持用戶自定義函數和動態正則表達式等先進功能,是linux/unix下的一個強大編程工具。它在命令行中使用,但更多是作為腳本來使用。awk有很多內建的功能,比如數組、函數等,這是它和C語言的相同之處,靈活性是awk最大的優勢。
語法形式:
awk [options] 'script' var=value file(s) awk [options] -f scriptfile var=value file(s)
常用命令選項
- -F fs fs指定輸入分隔符,fs可以是字符串或正則表達式,如-F:
- -v var=value 賦值一個用戶定義變量,將外部變量傳遞給awk
- -f scripfile 從腳本文件中讀取awk命令
- -m[fr] val 對val值設置內在限制,-mf選項限制分配給val的最大塊數目;-mr選項限制記錄的最大數目。這兩個功能是Bell實驗室版awk的擴展功能,在標准awk中不適用
模式:
- /正則表達式/:使用通配符的擴展集。
- 關系表達式:使用運算符進行操作,可以是字符串或數字的比較測試。
- 模式匹配表達式:用運算符
~
(匹配)和~!
(不匹配)。 - BEGIN語句塊、pattern語句塊、END語句塊
操作由一個或多個命令、函數、表達式組成,之間由換行符或分號隔開,並位於大括號內,主要部分是:
- 變量或數組賦值
- 輸出命令
- 內置函數
- 控制流語句
awk腳本基本結構:
awk 'BEGIN{ print "start" } pattern{ commands } END{ print "end" }' file
例:
一個awk腳本通常由:BEGIN語句塊、能夠使用模式匹配的通用語句塊、END語句塊3部分組成,這三個部分是可選的。任意一個部分都可以不出現在腳本中,腳本通常是被單引號或雙引號中
awk 'BEGIN{ i=0 } { i++ } END{ print i }' filename awk "BEGIN{ i=0 } { i++ } END{ print i }" filename
awk工作原理:
awk 'BEGIN{ commands } pattern{ commands } END{ commands }'
- 第一步:執行
BEGIN{ commands }
語句塊中的語句; - 第二步:從文件或標准輸入(stdin)讀取一行,然后執行
pattern{ commands }
語句塊,它逐行掃描文件,從第一行到最后一行重復這個過程,直到文件全部被讀取完畢。 - 第三步:當讀至輸入流末尾時,執行
END{ commands }
語句塊。
BEGIN語句塊在awk開始從輸入流中讀取行之前被執行,這是一個可選的語句塊,比如變量初始化、打印輸出表格的表頭等語句通常可以寫在BEGIN語句塊中。
END語句塊在awk從輸入流中讀取完所有的行之后即被執行,比如打印所有行的分析結果這類信息匯總都是在END語句塊中完成,它也是一個可選語句塊。
pattern語句塊中的通用命令是最重要的部分,它也是可選的。如果沒有提供pattern語句塊,則默認執行{ print }
,即打印每一個讀取到的行,awk讀取的每一行都會執行該語句塊。
內置變量:
說明:[A][N][P][G]表示第一個支持變量的工具,[A]=awk、[N]=nawk、[P]=POSIXawk、[G]=gawk
$n 當前記錄的第n個字段,比如n為1表示第一個字段,n為2表示第二個字段。 $0 這個變量包含執行過程中當前行的文本內容。 [N] ARGC 命令行參數的數目。 [G] ARGIND 命令行中當前文件的位置(從0開始算)。 [N] ARGV 包含命令行參數的數組。 [G] CONVFMT 數字轉換格式(默認值為%.6g)。 [P] ENVIRON 環境變量關聯數組。 [N] ERRNO 最后一個系統錯誤的描述。 [G] FIELDWIDTHS 字段寬度列表(用空格鍵分隔)。 [A] FILENAME 當前輸入文件的名。 [P] FNR 同NR,但相對於當前文件。 [A] FS 字段分隔符(默認是任何空格)。 [G] IGNORECASE 如果為真,則進行忽略大小寫的匹配。 [A] NF 表示字段數,在執行過程中對應於當前的字段數。 [A] NR 表示記錄數,在執行過程中對應於當前的行號。 [A] OFMT 數字的輸出格式(默認值是%.6g)。 [A] OFS 輸出字段分隔符(默認值是一個空格)。 [A] ORS 輸出記錄分隔符(默認值是一個換行符)。 [A] RS 記錄分隔符(默認是一個換行符)。 [N] RSTART 由match函數所匹配的字符串的第一個位置。 [N] RLENGTH 由match函數所匹配的字符串的長度。 [N] SUBSEP 數組下標分隔符(默認值是34)。
使用print $NF
可以打印出一行中的最后一個字段,使用$(NF-1)
則是打印倒數第二個字段,其他以此類推
一個每一行中第一個字段值累加的例子:
seq 5 | awk 'BEGIN{ sum=0; print "總和:" } { print $1"+"; sum+=$1 } END{ print "等於"; print sum }' 總和: 1+ 2+ 3+ 4+ 5+ 等於 15
遍歷計數,文件中所以字段出現次數:
/dev/mapper/centos-root / xfs defaults 0 0 UUID=471b8830-f6fc-4157-9004-5660a64cb25b /boot xfs defaults 0 0 /dev/mapper/centos-home /home xfs defaults 0 0 /dev/mapper/centos-swap swap swap defaults 0 0 [root@localhost ~]# awk '{for(i=1;i<=NF;i++){count[$i]++}}END{for(i in count){print i,count[i]}}' /etc/fstab
END遍歷所以行,第一個for遍歷一行中的每一個字段,這樣就完成了全文遍歷 18:12:55 1 man 1 and/or 1 maintained 1 xfs 3 /dev/mapper/centos-root 1 Accessible 1 # 7
開發Shell腳本判斷系統根分區剩余空間的大小,如果低於1000MB就提示不足,否則提示充足。
kongjian=`df -h|grep "/dev/sda1" |awk '{print $4}'|cut -d"M" -f 1` if [ $kongjian -lt 1000 ];then echo "內存不足了熬" else echo "內存充足熬" fi
遍歷計數,每一行中某一列的字段出現次數:
172.16.100.153 - - [22/Aug/2019:14:53:16 +0800] "GET /centos7/Packages/iwl3945-firmware-15.32.2.9-56.el7.noarch.rpm HTTP/1.1" 200 92000 "-" "urlgrabber/3.10 yum/3.4.3" 172.16.100.153 - - [22/Aug/2019:14:53:16 +0800] "GET /centos7/Packages/iwl6000-firmware-9.221.4.1-56.el7.noarch.rpm HTTP/1.1" 200 172668 "-" "urlgrabber/3.10 yum/3.4.3" [root@localhost ~]# awk '{http_ac[$4]++}END{for(i in http_ac){print i,http_ac[i]}}' /var/log/httpd/access_log 取文件中第4列,利用awk逐行,end讀取所有行后繼續執行,也就是取到了一個數組,以取到的字符串為角標,
數組內容由自加產生,為次數,for循環從數組中讀取次數輸出
[22/Aug/2019:14:49:59 1 [22/Aug/2019:14:50:30 7 [22/Aug/2019:14:50:31 13 [22/Aug/2019:14:36:41 40 [22/Aug/2019:14:36:42 125 [22/Aug/2019:14:36:43 166 [22/Aug/2019:14:36:44 153