awk是一種模式掃描和處理工具,相對于grep的查找,sed的編輯,它在對數據進行分析生成報表時顯得尤為強大。awk通過逐行遍歷一個或多個文件的方式,查找模式匹配到的行,而后以指定的分隔符(缺省為空格)進行切片,然后針對切片數據進行處理和分析。事實上,gawk有自己的語言,其本身就相當于一個解釋器,允許用戶創建簡短的程序讀取輸入文件,對輸入數據執行排序、計算以及生成報表操作,甚至可以類似bash shell實現諸如循環、數組、條件判斷、函數、變量等功能,進而完成更為復雜的數據分析處理任務。
Gawk
gawk(GNU awk)是UNIX awk的GNU版,為方便linux用戶使用,通常將/bin/awk以符號鏈接方式鏈接到/bin/gawk,以迎合用戶的使用習慣。(下文有提到gawk的地方均以awk代替)
awk的使用方式
1、命令行方式
awk [-F field-separator] ‘COMMAND’inputfiles
//其中COMMAND是awk的執行命令,用來處理數據,[-F field-separator]是可選選項,inputfiles是待處理文件。
//awk使用中,需要處理的文件,逐行使用分隔符分割成若干個字段,稱之為域,分隔符默認是空格,可使用-F選項來指定分隔符
2、shell腳本模式
將所需執行的awk命令插入awk腳本文件,然后在首行設置命令解釋器為#!/bin/awk,通過鍵入腳本名的方式調用。
3、所有awk命令寫入到一個單獨的文件,當處理同一類文件需求時,使用awk -f awk-script inputfiles調用之,其中awk-script指awk腳本。
awk的基本語法
awk [OPTION] 'program' FILE1 FILE2…
program:PATTERN{ACTION STATEMENT} //program由語句組成,各語句之間使用;隔開,整個program要用單引號引起來
OPTION:選項
-F:指定分割符
例,指定分隔符為“:”,打印出系統上各用戶名和morenshell
# awk -F: '{print $1,$7}' /etc/passwd
-v:指定變量
例,通過-v選項指定變量a=hello awk 然后將其打印出來
# awk -v a="hello awk" '{print a}'
另外,也可以通過特殊模式BEGIN(模式下述)來指定變量,如上例,也可以這樣寫
# awk 'BEGIN{a="hello awk"}{print a}'
-f:指定腳本文件
awk變量
awk的變量,可分類為內置變量和自定義變量
1、內置變量
2、自定義變量
自定義變量有兩種方式(上文基本語法中已有示例,此處不再贅述),但是,在腳本中仍然可以聲明變量。
(1)、awk -v VARIABLE_NAME VARIABLE_VALUE 'program' inputfiles
(2)、awk 'BEGIN{VARIABLE_NAME VARIABLE_VALUE}ACTION STATEMENT}' inputfiles
3、變量使用示例
(1)、FS輸入分隔符,默認為空格
例如,默認分隔符使用awk提取/etc/inittab中的“#”,如下圖可以看到,如果以空格分割,第一個域即為#(忽略最后一行)
# awk '{print $1}' /etc/inittab //效果如下(最后一行請忽略)
以“:”為分隔符,提取系統中用戶名以及用戶默認
# awk -v FS=":" '{print $1,$7}' /etc/passwd
(2)、輸出分隔符,默認為空格(如上圖上例顯示結果),接上例,以:為輸出分隔符顯示輸出結果
# awk -v FS=":" -v OFS=":" '{print $1,$7}' /etc/passwd
(3)、NR和FNR
顯示/etc/{inittab,passwd}所有內容以及行數
# awk '{print NR,$0}' /etc/{inittab,passwd}//看下圖,行數不分開計數
# awk '{print FNR,$0}' /etc/{inittab,passwd}//看下圖,使用FNR單獨計數行數
# awk 'BEGIN{print "filename","alone_lines","unit_lines"}{print FILENAME,NR,FNR}' /etc/{passwd,inittab,group}//還可以這樣寫來分別顯示總行號和單獨行號,此處不再貼圖
(4)、ARGC顯示參數個數
# awk -F: '{print $1}END{print ARGC}' /etc/passwd //如下圖,顯示參數為二(經驗證,貌似program也被識別成為一個參數,再加上后面的文件故為2個參數?)
awk的模式
1、Regular Expression 正則表達式
如其名,使用正則表達式匹配模式,在需要注意的是,在awk中使用正則表達式,匹配字符串要使用雙斜線括起來,而后匹配到的行將被切片并分析處理,反之將略過。
取出/etc/passwd中包含root的行并打印出用戶名和默認shell
# awk -F: ‘/root/ {print $1,$7}' /etc/passwd
2、Expression 表達式,當表達式的值為真(非零或非空)的行被匹配,僅處理匹配到的行
# awk -F: '$3>=500{print $1,$2,$3}' /etc/passwd
在此列出awk的常用操作符
如果模式自身是=,要寫為/=/
條件表達式:
selector?if-true-express:if-false-express 只能是表達式不能使語句
條件表達式中,“:”兩側僅允許使用表達式而不能使用語句
例
# awk -F: '$3>=500?utype="common user":utype="admin or system user"{print $1 "is" utype} /etc/passwd
3、range行范圍,有兩種方式來定義此范圍
(1)、pattern1,pattern2
從匹配到pattern1的行開始到匹配到pattern2的行為知,此范圍的行被awk action處理
# awk 'NR==1,NR==10{print $1,$3,$7} /etc/passwd
4、特殊模式BEGIN和END
(1)、BEGIN在讀取任何輸入之前執行一次語句
# awk 'BEGIN{FS=":";OFS=":"}/root/{print $1,$3,$7} /etc/passwd
(2)、END在讀取所有輸入之后執行一次語句
# awk 'BEGIN{FS=":";OFS=":"}/root/{print $1,$3,$7}END{print "The end!"}' /etc/passwd
5、空模式
如果不指定模式則匹配文件中的所有行
awk重定向
1、輸出重定向
awk可以使用shell的重定向符重定向輸出,同樣>代表覆蓋式輸出,>>代表追加。
覆蓋式重定向
追加重定向效果
2、輸入重定向
輸入重定向需用到getline函數。getline從標準輸入、管道或者當前正在處理的文件之外的其他輸入文件獲得輸入。它負責從輸入獲得下一行的內容,并給NF,NR和FNR等內建變量賦值。如果得到一條記錄,getline函數返回1,如果到達文件的末尾就返回0,如果出現錯誤,例如打開文件失敗,就返回-1,可以結合到while等流控制語句使用。
通過例子說明輸入重定向用法
(1)、awk 'BEGIN{"date" | getline d; print d}'
getling函數讀取date命令的輸出結果并將其賦值給自定義變量d,然后打印變量d
(2)、awk 'BEGIN{"date" | getline d; split(d,mon); print mon[3]}'
getine函數讀取date命令輸出的結果并賦值給自定義變量d,split函數將變量d轉化為數組mon,然后打印數組mon的第三個元素。
(3)、awk 'BEGIN{while("ls" | getline) print}'
getline函數讀取ls命令的輸出結果而后打印顯示
awk之print和printf
1、print
用法:print item1,item2….
要點:
(1)、各item之間使用,號隔開,輸出時默認以空格分隔
(2)、輸出的item可以是字符串或數值、當前分隔出來的域(字段,如$1)、變量或awk的表達式,數值會隱式轉換為字符串輸出。
(3)、print后面的item項可以省略,此時相當于打印$0即整行內容;print ""表示打印空白行。
例:
# awk 'BEGIN{print "line1","line2","line3"}'
# awk -F: '{print $1,$3,$7}' /etc/passwd
2、printf
用來格式話打印輸出內容
(1)、格式:
printf format,item1,ietm2,…
(2)、要點
printf需要指定format;
format用于指定后面每個item的格式;
printf不能自行換行,如需換行需給定\n;
使用修飾符可以使輸出格式更加美觀。
(3)、format的格式指示符,以%開始,后跟一個字符
%c:顯示字符的ASCII嗎
%d,%i:十進制整數
%e,%E:科學計數法顯示數值
%f:顯示浮點數本身
%g,%G:以科學計數法格式或浮點數顯示數值
%s:顯示字符串
%u:顯示無符號整數
%%:顯示%自身
修飾符
#:字段的顯示寬度
.#:取值精度
-:左對齊
=+:顯示數值的符號
(4)、例:
取出系統用戶的用戶名和默認shell,要求用戶名左對齊,占用15個字符,字符串顯示;要求默認shell左對齊,占用20字符,字符串顯示
awk -F: ‘{printf "%-15s %-20s\n",$1,$7}' /etcpasswd
使用顯示浮點數自身(%f)的方式顯示,會自動補全精度,長于精度部分將會執行四舍五入
# awk 'BEGIN{printf "%f\n",3.15}'
當使用數字來定義字段占用字符長度時,要放在其它修飾符前面;小數點后面的數字代表精度
# awk 'BEGIN{printf "%-15.2\n",3.15}'
awk之action
1、常見action
(1)、表達式 Expression
(2)、控制語句 Control statements
(3)、組合語句 Commpound statments
(4)、輸入語句 Input statments
(5)、輸出語句 Output statements
2、awk常見控制語句以及使用示例
(1)、if-else語句 格式:if (condition) {then body} else {else body}
# awk -F: '{if($3>=500{print $1 "is a common user"} else {print $1 "is admin or systemuser"}' /etc/passwd
uid號大于等于500的顯示為普通用戶,小于500的顯示為管理員或系統用戶。
# awk -F: '{if(NF>=8){print}}' /etc/inittab
打印顯示以冒號切割形成字段大于等于8的行
(2)、while語句 格式: 格式:while (condition) {while body}
awk '{i=1;while(i<=NF){printf "%s ",$i;i+=2}; print ""}' /etc/inittab
打印輸出/etc/inittab中的奇數字段
打印出字符大于等于6的字段
# awk '{i=1;while(i<=NF{if(length($i<=6){print $i};i++}}' /etc/inittab
(3)、do-while循環 格式:格式:do {do-while body} while (condition)
# awk 'BEGIN{sum=0;i=0;do{sum+=i;i+=}while{i<=100};print sum;}'
求和1-100
(4)、for循環 格式:for (variable assignment; condition; iteration process) {for body}
# awk '{for(i=1,i<=NF,i+=2){printf "%s ",$1};print ""}' /etc/inittab
打印出/etc/inittab中的每行的奇數字段
for循環還可以用來遍歷數組 格式:for (i in array) {for body}
# awk 'BEGIN{"date" | getline d; split(d,test);for (i in test) print test[i]}'
break 用于在滿足條件的情況下跳出循環;continue用于在滿足條件時忽略后面的語句,直接返回循環的頂端
(5)、next提前結束本行處理,進入下一行處理
取uid為奇數的用戶和uid
# awk -F: '{if($3%2==0) next;print $1,$3}' /etc/passwd
(6)、數組
關聯數組
array[index-expression]index-expression:可以使用任意字符串;如果某數組元素事先不存在,那么在引用時,awk會自動創建次元素并將其初始化為空串;因此,要判斷某數組是否存在某元素,必須使用“index in array”這種格式A[first]="hello awk"print A[second]要遍歷數組中的每一個元素,需要使用如下特殊結構:for (var in array) {for body}期中var會遍歷array的索引,而非元素的值
(7)、awk的內置函數 split(string,array[,fieldsep[,seps]])能夠將string標示的字符串以fieldsep為分隔符進行切片,并切片后的結果保存至array為名的數組中;數組下表從1開始
# awk 'BEGIN{split("root:x:0:0",user,":");for (i in user) print user[i]}'
由于本人水平有限,awk的使用先總結到這里吧,在以后的使用中再深入研究。
原創文章,作者:Silently,如若轉載,請注明出處:http://www.www58058.com/6553