天天看點

linux awk指令詳解

原文連結 : http://blog.chinaunix.net/uid-23302288-id-3785105.html

awk是行處理器: 相比較螢幕處理的優點,在處理龐大檔案時不會出現記憶體溢出或是處理緩慢的問題,通常用來格式化文本資訊

awk處理過程: 依次對每一行進行處理,然後輸出

awk指令形式:

awk [-F|-f|-v] ‘BEGIN{} //{command1; command2} END{}’ file

 [-F|-f|-v]   大參數,-F指定分隔符,-f調用腳本,-v定義變量 var=value

'  '          引用代碼塊

BEGIN   初始化代碼塊,在對每一行進行處理之前,初始化代碼,主要是引用全局變量,設定FS分隔符

//           比對代碼塊,可以是字元串或正規表達式

{}           指令代碼塊,包含一條或多條指令

;          多條指令使用分号分隔

END      結尾代碼塊,在對每一行進行處理之後再執行的代碼塊,主要是進行最終計算或輸出結尾摘要資訊

特殊要點:

$0           表示整個目前行

$1           每行第一個字段

NF          字段數量變量

NR          每行的記錄号,多檔案記錄遞增

FNR        與NR類似,不過多檔案記錄不遞增,每個檔案都從1開始

\t            制表符

\n           換行符

FS          BEGIN時定義分隔符

RS       輸入的記錄分隔符, 預設為換行符(即文本是按一行一行輸入)

~            比對,與==相比不是精确比較

!~           不比對,不精确比較

==         等于,必須全部相等,精确比較

!=           不等于,精确比較

&&      邏輯與

||             邏輯或

+            比對時表示1個或1個以上

/[0-9][0-9]+/   兩個或兩個以上數字

/[0-9][0-9]*/    一個或一個以上數字

FILENAME 檔案名

OFS      輸出字段分隔符, 預設也是空格,可以改為制表符等

ORS        輸出的記錄分隔符,預設為換行符,即處理結果也是一行一行輸出到螢幕

-F'[:#/]'   定義三個分隔符

print & $0

print 是awk列印指定内容的主要指令

awk '{print}'  /etc/passwd   ==   awk '{print $0}'  /etc/passwd  

awk '{print " "}' /etc/passwd                                           //不輸出passwd的内容,而是輸出相同個數的空行,進一步解釋了awk是一行一行處理文本

awk '{print "a"}'   /etc/passwd                                        //輸出相同個數的a行,一行隻有一個a字母

awk -F":" '{print $1}'  /etc/passwd 

awk -F: '{print $1; print $2}'   /etc/passwd                   //将每一行的前二個字段,分行輸出,進一步了解一行一行處理文本

awk  -F: '{print $1,$3,$6}' OFS="\t" /etc/passwd        //輸出字段1,3,6,以制表符作為分隔符

-f指定腳本檔案

awk -f script.awk  file

BEGIN{

FS=":"

}

{print $1}               //效果與awk -F":" '{print $1}'相同,隻是分隔符使用FS在代碼自身中指定

awk 'BEGIN{X=0} /^$/{ X+=1 } END{print "I find",X,"blank lines."}' test 

I find 4 blank lines.

 ls -l|awk 'BEGIN{sum=0} !/^d/{sum+=$5} END{print "total size is",sum}'                    //計算檔案大小

total size is 17487

-F指定分隔符

$1 指指定分隔符後,第一個字段,$3第三個字段, \t是制表符

一個或多個連續的空格或制表符看做一個定界符,即多個空格看做一個空格

awk -F":" '{print $1}'  /etc/passwd

awk -F":" '{print $1 $3}'  /etc/passwd                       //$1與$3相連輸出,不分隔

awk -F":" '{print $1,$3}'  /etc/passwd                       //多了一個逗号,$1與$3使用空格分隔

awk -F":" '{print $1 " " $3}'  /etc/passwd                  //$1與$3之間手動添加空格分隔

awk -F":" '{print "Username:" $1 "\t\t Uid:" $3 }' /etc/passwd       //自定義輸出  

awk -F: '{print NF}' /etc/passwd                                //顯示每行有多少字段

awk -F: '{print $NF}' /etc/passwd                              //将每行第NF個字段的值列印出來

 awk -F: 'NF==4 {print }' /etc/passwd                       //顯示隻有4個字段的行

awk -F: 'NF>2{print $0}' /etc/passwd                       //顯示每行字段數量大于2的行

awk '{print NR,$0}' /etc/passwd                                 //輸出每行的行号

awk -F: '{print NR,NF,$NF,"\t",$0}' /etc/passwd      //依次列印行号,字段數,最後字段值,制表符,每行内容

awk -F: 'NR==5{print}'  /etc/passwd                         //顯示第5行

awk -F: 'NR==5 || NR==6{print}'  /etc/passwd       //顯示第5行和第6行

route -n|awk 'NR!=1{print}'                                       //不顯示第一行

//比對代碼塊

//純字元比對   !//純字元不比對   ~//字段值比對    !~//字段值不比對   ~/a1|a2/字段值比對a1或a2   

awk '/mysql/' /etc/passwd

awk '/mysql/{print }' /etc/passwd

awk '/mysql/{print $0}' /etc/passwd                   //三條指令結果一樣

awk '!/mysql/{print $0}' /etc/passwd                  //輸出不比對mysql的行

awk '/mysql|mail/{print}' /etc/passwd

awk '!/mysql|mail/{print}' /etc/passwd

awk -F: '/mail/,/mysql/{print}' /etc/passwd         //區間比對

awk '/[2][7][7]*/{print $0}' /etc/passwd               //比對包含27為數字開頭的行,如27,277,2777...

awk -F: '$1~/mail/{print $1}' /etc/passwd           //$1比對指定内容才顯示

awk -F: '{if($1~/mail/) print $1}' /etc/passwd     //與上面相同

awk -F: '$1!~/mail/{print $1}' /etc/passwd          //不比對

awk -F: '$1!~/mail|mysql/{print $1}' /etc/passwd        

IF語句

必須用在{}中,且比較内容用()擴起來

awk -F: '{if($1~/mail/) print $1}' /etc/passwd                                       //簡寫

awk -F: '{if($1~/mail/) {print $1}}'  /etc/passwd                                   //全寫

awk -F: '{if($1~/mail/) {print $1} else {print $2}}' /etc/passwd            //if...else...

條件表達式

==   !=   >   >=  

awk -F":" '$1=="mysql"{print $3}' /etc/passwd  

awk -F":" '{if($1=="mysql") print $3}' /etc/passwd          //與上面相同 

awk -F":" '$1!="mysql"{print $3}' /etc/passwd                 //不等于

awk -F":" '$3>1000{print $3}' /etc/passwd                      //大于

awk -F":" '$3>=100{print $3}' /etc/passwd                     //大于等于

awk -F":" '$3<1{print $3}' /etc/passwd                            //小于

awk -F":" '$3<=1{print $3}' /etc/passwd                         //小于等于

邏輯運算符

&& || 

awk -F: '$1~/mail/ && $3>8 {print }' /etc/passwd         //邏輯與,$1比對mail,并且$3>8

awk -F: '{if($1~/mail/ && $3>8) print }' /etc/passwd

awk -F: '$1~/mail/ || $3>1000 {print }' /etc/passwd       //邏輯或

awk -F: '{if($1~/mail/ || $3>1000) print }' /etc/passwd 

數值運算

awk -F: '$3 > 100' /etc/passwd    

awk -F: '$3 > 100 || $3 < 5' /etc/passwd  

awk -F: '$3+$4 > 200' /etc/passwd

awk -F: '/mysql|mail/{print $3+10}' /etc/passwd                    //第三個字段加10列印 

awk -F: '/mysql/{print $3-$4}' /etc/passwd                             //減法

awk -F: '/mysql/{print $3*$4}' /etc/passwd                             //求乘積

awk '/MemFree/{print $2/1024}' /proc/meminfo                  //除法

awk '/MemFree/{print int($2/1024)}' /proc/meminfo           //取整

輸出分隔符OFS

awk '$6 ~ /FIN/ || NR==1 {print NR,$4,$5,$6}' OFS="\t" netstat.txt

awk '$6 ~ /WAIT/ || NR==1 {print NR,$4,$5,$6}' OFS="\t" netstat.txt        

//輸出字段6比對WAIT的行,其中輸出每行行号,字段4,5,6,并使用制表符分割字段

輸出處理結果到檔案

①在指令代碼塊中直接輸出    route -n|awk 'NR!=1{print > "./fs"}'   

②使用重定向進行輸出           route -n|awk 'NR!=1{print}'  > ./fs

格式化輸出

netstat -anp|awk '{printf "%-8s %-8s %-10s\n",$1,$2,$3}' 

printf表示格式輸出

%格式化輸出分隔符

-8長度為8個字元

s表示字元串類型

列印每行前三個字段,指定第一個字段輸出字元串類型(長度為8),第二個字段輸出字元串類型(長度為8),

第三個字段輸出字元串類型(長度為10)

netstat -anp|awk '$6=="LISTEN" || NR==1 {printf "%-10s %-10s %-10s \n",$1,$2,$3}'

netstat -anp|awk '$6=="LISTEN" || NR==1 {printf "%-3s %-10s %-10s %-10s \n",NR,$1,$2,$3}'

awk -F: '{if($3>100) print "large"; else print "small"}' /etc/passwd

small

large

awk -F: 'BEGIN{A=0;B=0} {if($3>100) {A++; print "large"} else {B++; print "small"}} END{print A,"\t",B}' /etc/passwd 

                                                                                                                  //ID大于100,A加1,否則B加1

awk -F: '{if($3<100) next; else print}' /etc/passwd                         //小于100跳過,否則顯示

awk -F: 'BEGIN{i=1} {if(i<NF) print NR,NF,i++ }' /etc/passwd   

awk -F: 'BEGIN{i=1} {if(i<NF) {print NR,NF} i++ }' /etc/passwd

另一種形式

awk -F: '{print ($3>100 ? "yes":"no")}'  /etc/passwd 

awk -F: '{print ($3>100 ? $3":\tyes":$3":\tno")}'  /etc/passwd

while語句

awk -F: 'BEGIN{i=1} {while(i<NF) print NF,$i,i++}' /etc/passwd 

7 root 1

7 x 2

7 0 3

7 0 4

7 root 5

7 /root 6

數組

netstat -anp|awk 'NR!=1{a[$6]++} END{for (i in a) print i,"\t",a[i]}'

netstat -anp|awk 'NR!=1{a[$6]++} END{for (i in a) printf "%-20s %-10s %-5s \n", i,"\t",a[i]}'

9523                               1     

9929                               1     

LISTEN                            6     

7903                               1     

3038/cupsd                   1     

7913                               1     

10837                             1     

9833                               1     

應用1

awk -F: '{print NF}' helloworld.sh                                                       //輸出檔案每行有多少字段

awk -F: '{print $1,$2,$3,$4,$5}' helloworld.sh                                 //輸出前5個字段

awk -F: '{print $1,$2,$3,$4,$5}' OFS='\t' helloworld.sh                 //輸出前5個字段并使用制表符分隔輸出

awk -F: '{print NR,$1,$2,$3,$4,$5}' OFS='\t' helloworld.sh           //制表符分隔輸出前5個字段,并列印行号

應用2

awk -F'[:#]' '{print NF}'  helloworld.sh                                                  //指定多個分隔符: #,輸出每行多少字段

awk -F'[:#]' '{print $1,$2,$3,$4,$5,$6,$7}' OFS='\t' helloworld.sh   //制表符分隔輸出多字段

應用3

awk -F'[:#/]' '{print NF}' helloworld.sh                                               //指定三個分隔符,并輸出每行字段數

awk -F'[:#/]' '{print $1,$2,$3,$4,$5,$6,$7,$8,$9,$10,$11,$12}' helloworld.sh     //制表符分隔輸出多字段

應用4

計算/home目錄下,普通檔案的大小,使用KB作為機關

ls -l|awk 'BEGIN{sum=0} !/^d/{sum+=$5} END{print "total size is:",sum/1024,"KB"}'

ls -l|awk 'BEGIN{sum=0} !/^d/{sum+=$5} END{print "total size is:",int(sum/1024),"KB"}'         //int是取整的意思

應用5

統計netstat -anp 狀态為LISTEN和CONNECT的連接配接數量分别是多少

netstat -anp|awk '$6~/LISTEN|CONNECTED/{sum[$6]++} END{for (i in sum) printf "%-10s %-6s %-3s \n", i," ",sum[i]}'

應用6

統計/home目錄下不同使用者的普通檔案的總數是多少?

ls -l|awk 'NR!=1 && !/^d/{sum[$3]++} END{for (i in sum) printf "%-6s %-5s %-3s \n",i," ",sum[i]}'   

mysql        199 

root           374 

統計/home目錄下不同使用者的普通檔案的大小總size是多少?

ls -l|awk 'NR!=1 && !/^d/{sum[$3]+=$5} END{for (i in sum) printf "%-6s %-5s %-3s %-2s \n",i," ",sum[i]/1024/1024,"MB"}'

應用7

輸出成績表

awk 'BEGIN{math=0;eng=0;com=0;printf "Lineno.   Name    No.    Math   English   Computer    Total\n";printf "------------------------------------------------------------\n"}{math+=$3; eng+=$4; com+=$5;printf "%-8s %-7s %-7s %-7s %-9s %-10s %-7s \n",NR,$1,$2,$3,$4,$5,$3+$4+$5} END{printf "------------------------------------------------------------\n";printf "%-24s %-7s %-9s %-20s \n","Total:",math,eng,com;printf "%-24s %-7s %-9s %-20s \n","Avg:",math/NR,eng/NR,com/NR}' test0

[root@localhost home]# cat test0 

Marry   2143 78 84 77

Jack    2321 66 78 45

Tom     2122 48 77 71

Mike    2537 87 97 95

Bob     2415 40 57 62

linux awk指令詳解

awk手冊

http://www.chinaunix.net/old_jh/7/16985.html

繼續閱讀