1. 程式人生 > >Linux之awk命令詳解

Linux之awk命令詳解

AWK介紹
0.awk有3個不同版本: awk、nawk和gawk,未作特別說明,一般指gawk。
1.awk語言的最基本功能是在檔案或字串中基於指定規則來分解抽取資訊,也可以基於指定的規則來輸出資料。完整的awk指令碼通常用來格式化文字檔案中的資訊。
2.三種方式呼叫awk
1) awk [opion] 'awk_script' input_file1 [input_file2 ...]
awk的常用選項option有;
① -F fs : 使用fs作為輸入記錄的欄位分隔符,如果省略該選項,awk使用環境變數IFS的值
② -f filename : 從檔案filename中讀取awk_script
③ -v var=value : 為awk_script設定變數
2) 將awk_script放入指令碼檔案並以 #!/bin/awk -f 作為首行,給予該指令碼可執行許可權,然後在shell下通過鍵入該指令碼的指令碼名呼叫之。
3) 將所有的awk_script插入一個單獨指令碼檔案,然後呼叫: awk -f awk指令碼檔案 input_file(s)

3. awk的執行過程
1) awk_script的組成:
① awk_script可以由一條或多條awk_cmd組成,兩條awk_cmd之間一般以NEWLINE分隔
② awk_cmd由兩部分組成: awk_pattern { actions }
③ awk_script可以被分成多行書寫,必須確保整個awk_script被單引號括起來。
2) awk命令的一般形式:
awk ' BEGIN { actions }
awk_pattern1 { actions }
............
awk_patternN { actions }
END { actions }
' inputfile
其中 BEGIN { actions } 和 END { actions } 是可選的。
3) awk的執行過程:
① 如果BEGIN 區塊存在,awk執行它指定的actions。
② awk從輸入檔案中讀取一行,稱為一條輸入記錄。(如果輸入檔案省略,將從標準輸入讀取)
③ awk將讀入的記錄分割成欄位,將第1個欄位放入變數$1中,第2個欄位放入$2,以此類推。$0表示整條記錄。欄位分隔符使用shell環境變數IFS 或由引數指定。
④ 把當前輸入記錄依次與每一個awk_cmd中awk_pattern比較,看是否匹配,如果相匹配,就執行對應的actions。如果不匹配,就跳過對應的actions,直到比較完所有的awk_cmd。
⑤ 當一條輸入記錄比較了所有的awk_cmd後,awk讀取輸入的下一行,繼續重複步驟③和④,這個過程一直持續,直到awk讀取到檔案尾。
⑥ 當awk讀完所有的輸入行後,如果存在END,就執行相應的actions。

4) iput_file可以是多於一個檔案的檔案列表,awk將按順序處理列表中的每個檔案。
5) 一條awk_cmd的awk_pattern可以省略,省略時不對輸入記錄進行匹配比較就執行相應的actions。一條awk_cmd的actions 也可以省略,省略時預設的動作為列印當前輸入記錄(print $0) 。一條awk_cmd中的awk_pattern和actions不能同時省略。
6) BEGIN區塊和END區塊別位於awk_script的開頭和結尾。awk_script中只有END區塊或者只有BEGIN區塊是被允許的。如果 awk_script中只有BEGIN { actions } ,awk不會讀取input_file。
7) awk把輸入檔案的資料讀入記憶體,然後操作記憶體中的輸入資料副本,awk不會修改輸入檔案的內容。
8) awk的總是輸出到標準輸出,如果想讓awk輸出到檔案,可以使用重定向。

4.awk_pattern
awk_pattern模式部分決定actions動作部分何時觸發及觸發actions。awk_pattern可以是以下幾種型別:
1) 正則表示式用作awk_pattern: /regexp/
① awk中正則表示式匹配操作中經常用到的字元:
/ ^ $ . [] | () * // 通用的regexp元字元
+ : 匹配其前的單個字元一次以上,是awk自有的元字元,不適用於grep或sed等
? : 匹配其前的單個字元1次或0次,是awk自有的元字元,不適用於grep或sed等
② 舉例:
awk '/ */$0/.[0-9][0-9].*/' input_file
2) 布林表示式用作awk_pattern,表示式成立時,觸發相應的actions執行。
① 表示式中可以使用變數(如欄位變數$1,$2等)和/regexp/
② 布林表示式中的操作符:
關係操作符: < > <= >= == !=
匹配操作符: value ~ /regexp/ 如果value匹配/regexp/,則返回真
value !~ /regexp/ 如果value不匹配/regexp/,則返回真
舉例: awk '$2 > 10 {print "ok"}' input_file
awk '$3 ~ /^d/ {print "ok"}' input_file
③ &&(與) 和 ||(或) 可以連線兩個/regexp/或者布林表示式,構成混合表示式。!(非) 可以用於布林表示式或者/regexp/之前。
舉例: awk '($1 < 10 ) && ($2 > 10) {print "ok"}' input_file
awk '/^d/ || /x$/ {print "ok"}' input_file
④ 其它表示式用作awk_script,如賦值表示式等
eg: awk '(tot+=$6); END{print "total points :" tot }' input_file // 分號不能省略
awk 'tot+=$6 {print $0} END{print "total points :" tot }' input_file // 與上面等效

awk 用法例舉:
變數名 含義
ARGC 命令列變元個數
ARGV 命令列變元陣列
FILENAME 當前輸入檔名
FNR 當前檔案中的記錄號
FS 輸入域分隔符,預設為一個空格
RS 輸入記錄分隔符
NF 當前記錄裡域個數
NR 到目前為止記錄數
OFS 輸出域分隔符
ORS 輸出記錄分隔符

1、awk '/101/' file 顯示檔案file中包含101的匹配行。
awk '/101/,/105/' file
awk '$1 == 5' file
awk '$1 == "CT"' file 注意必須帶雙引號
awk '$1 * $2 >100 ' file
awk '$2 >5 && $2<=15' file
2、awk '{print NR,NF,$1,$NF,}' file 顯示檔案file的當前記錄號、域數和每一行的第一個和最後一個域。
awk '/101/ {print $1,$2 + 10}' file 顯示檔案file的匹配行的第二個域加10。
awk '/101/ {print $1$2}' file
awk '/101/ {print $1 $2}' file 顯示檔案file的匹配行的第一、二個域,但顯示時域中間沒有分隔符。
3、df | awk '$4>1000000 ' 通過管道符獲得輸入,如:顯示第4個域滿足條件的行。
4、awk -F "|" '{print $1}' file 按照新的分隔符“|”進行操作。
awk 'BEGIN { FS="[: /t|]" }
{print $1,$2,$3}' file 通過設定輸入分隔符(FS="[: /t|]")修改輸入分隔符。

Sep="|"
awk -F $Sep '{print $1}' file 按照環境變數Sep的值做為分隔符。
awk -F '[ :/t|]' '{print $1}' file 按照正則表示式的值做為分隔符,這裡代表空格、:、TAB、|同時做為分隔符。
awk -F '[][]' '{print $1}' file 按照正則表示式的值做為分隔符,這裡代表[、]
5、awk -f awkfile file 通過檔案awkfile的內容依次進行控制。
cat awkfile
/101/{print "/047 Hello! /047"} --遇到匹配行以後列印 ' Hello! './047代表單引號。
{print $1,$2} --因為沒有模式控制,列印每一行的前兩個域。
6、awk '$1 ~ /101/ {print $1}' file 顯示檔案中第一個域匹配101的行(記錄)。
7、awk 'BEGIN { OFS="%"}
{print $1,$2}' file 通過設定輸出分隔符(OFS="%")修改輸出格式。
8、awk 'BEGIN { max=100 ;print "max=" max} BEGIN 表示在處理任意行之前進行的操作。
{max=($1 >max ?$1:max); print $1,"Now max is "max}' file 取得檔案第一個域的最大值。
(表示式1?表示式2:表示式3 相當於:
if (表示式1)
表示式2
else
表示式3
awk '{print ($1>4 ? "high "$1: "low "$1)}' file
9、awk '$1 * $2 >100 {print $1}' file 顯示檔案中第一個域匹配101的行(記錄)。
10、awk '{$1 == 'Chi' {$3 = 'China'; print}' file 找到匹配行後先將第3個域替換後再顯示該行(記錄)。
awk '{$7 %= 3; print $7}' file 將第7域被3除,並將餘數賦給第7域再列印。
11、awk '/tom/ {wage=$2+$3; printf wage}' file 找到匹配行後為變數wage賦值並列印該變數。
12、awk '/tom/ {count++;}
END {print "tom was found "count" times"}' file END表示在所有輸入行處理完後進行處理。
13、awk 'gsub(//$/,"");gsub(/,/,""); cost+=$4;
END {print "The total is $" cost>"filename"}' file gsub函式用空串替換$和,再將結果輸出到filename中。
1 2 3 $1,200.00
1 2 3 $2,300.00
1 2 3 $4,000.00

awk '{gsub(//$/,"");gsub(/,/,"");
if ($4>1000&&$4<2000) c1+=$4;
else if ($4>2000&&$4<3000) c2+=$4;
else if ($4>3000&&$4<4000) c3+=$4;
else c4+=$4; }
END {printf "c1=[%d];c2=[%d];c3=[%d];c4=[%d]/n",c1,c2,c3,c4}"' file
通過if和else if完成條件語句

awk '{gsub(//$/,"");gsub(/,/,"");
if ($4>3000&&$4<4000) exit;
else c4+=$4; }
END {printf "c1=[%d];c2=[%d];c3=[%d];c4=[%d]/n",c1,c2,c3,c4}"' file
通過exit在某條件時退出,但是仍執行END操作。
awk '{gsub(//$/,"");gsub(/,/,"");
if ($4>3000) next;
else c4+=$4; }
END {printf "c4=[%d]/n",c4}"' file
通過next在某條件時跳過該行,對下一行執行操作。


14、awk '{ print FILENAME,$0 }' file1 file2 file3>fileall 把file1、file2、file3的檔案內容全部寫到fileall中,格式為
列印檔案並前置檔名。
15、awk ' $1!=previous { close(previous); previous=$1 }
{print substr($0,index($0," ") +1)>$1}' fileall 把合併後的檔案重新分拆為3個檔案。並與原檔案一致。
16、awk 'BEGIN {"date"|getline d; print d}' 通過管道把date的執行結果送給getline,並賦給變數d,然後列印。
17、awk 'BEGIN {system("echo "Input your name://c""); getline d;print "/nYour name is",d,"/b!/n"}'
通過getline命令互動輸入name,並顯示出來。
awk 'BEGIN {FS=":"; while(getline< "/etc/passwd" >0) { if($1~"050[0-9]_") print $1}}'
列印/etc/passwd檔案中使用者名稱包含050x_的使用者名稱。

18、awk '{ i=1;while(i<NF) {print NF,$i;i++}}' file 通過while語句實現迴圈。
awk '{ for(i=1;i<NF;i++) {print NF,$i}}' file 通過for語句實現迴圈。
type file|awk -F "/" '
{ for(i=1;i<NF;i++)
{ if(i==NF-1) { printf "%s",$i }
else { printf "%s/",$i } }}' 顯示一個檔案的全路徑。
用for和if顯示日期
awk 'BEGIN {
for(j=1;j<=12;j++)
{ flag=0;
printf "/n%d月份/n",j;
for(i=1;i<=31;i++)
{
if (j==2&&i>28) flag=1;
if ((j==4||j==6||j==9||j==11)&&i>30) flag=1;
if (flag==0) {printf "%02d%02d ",j,i}
}
}
}'
19、在awk中呼叫系統變數必須用單引號,如果是雙引號,則表示字串
Flag=abcd
awk '{print '$Flag'}' 結果為abcd
awk '{print "$Flag"}' 結果為$Flag