awk

一.簡介

強大的文本分析工具,基於指定規則瀏覽和抽取信息。簡單來說awk就是把文件逐行的讀入,以空格爲默認分隔符將每行切片,切開的部分再進行各種分析處理。awk有3個不同版本: awk、nawk和gawk,未作特別說明,一般指gawk,gawk 是 AWK 的 GNU 版本。
awk其名稱得自於它的創始人 Alfred Aho 、Peter Weinberger 和 Brian Kernighan 姓氏的首個字母。實際上 AWK 的確擁有自己的語言: AWK 程序設計語言 , 三位創建者已將它正式定義爲“樣式掃描和處理語言”。
先執行BEGING,然後讀取文件,讀入有/n換行符分割的一條記錄,然後將記錄按指定的域分隔符劃分域,填充域,$0則表示所有域,$1表示第一個域,$n表示第n個域,隨後開始執行模式所對應的動作action。接着開始讀入第二條記錄······直到所有的記錄都讀完,最後執行END操作。

二.語法

awk '{pattern + action}' {filenames}
pattern 表示 AWK 在數據中查找的內容;action 是在找到匹配內容時所執行的一系列命令,命令之間;號隔開,沒有指定action,默認輸出整行的內容。pattern就是要表示的正則表達式,用斜槓括起來



三.調用awk方式

3.1命令行方式

awk [-F field-separator] 'commands' input-file(s)
其中,commands 是真正awk命令,[-F域分隔符]是可選的。 input-file(s) 是待處理的文件。

3.2 shell腳本方式

將所有的awk命令插入一個文件,並使awk程序可執行,然後awk命令解釋器作爲腳本的首行,一遍通過鍵入腳本名稱來調用。
相當於shell腳本首行的:#!/bin/sh
可以換成:#!/bin/awk

3.3 將所有的awk命令插入一個單獨文件

awk -f awk-script-file input-file(s)
其中,-f選項加載awk-script-file中的awk腳本,input-file(s)跟上面的是一樣的。


四.內置變量

點擊這裏 點擊這裏
ARGC 命令行參數個數
ARGV 命令行參數排列
ENVIRON 支持隊列中系統環境變量的使用
FILENAME awk瀏覽的文件名
FNR 瀏覽文件的記錄數
FS 設置輸入域分隔符,等價於命令行-F選項
NF 瀏覽記錄的域的個數
NR 已讀的記錄數
OFMT 輸出格式,形式同printf
OFS 輸出域分隔符
ORS 輸出記錄分隔符
RS 控制記錄分隔符

此外,$0變量是指整條記錄。$1表示當前行的第一個域,$2表示當前行的第二個域,......以此類推。

五.內置函數

5.1 算術函數

函數名 說明
atan2( y, x ) 返回 y/x 的反正切。
cos( x ) 返回 x 的餘弦;x 是弧度。
sin( x ) 返回 x 的正弦;x 是弧度。
exp( x ) 返回 x 冪函數。
log( x ) 返回 x 的自然對數。
sqrt( x ) 返回 x 平方根。
int( x ) 返回 x 的截斷至整數的值。
rand( ) 返回任意數字 n,其中 0 <= n < 1。
srand( [Expr] ) 將 rand 函數的種子值設置爲 Expr 參數的值,或如果省略 Expr 參數則使用某天的時間。返回先前的種子值。

如:$ awk 'BEGIN{srand();fr=int(100*rand());print fr;}'

5.2 字符串函數

函數 說明
sub( Ere, Repl, [ In ] ) 字符串替換,將匹配Ere的子串替換爲Repl,只替換第一次匹配到的,sub 函數返回替換的數量。如果未指定 In 參數,缺省值是整個記錄($0 記錄變量)。
gsub( Ere, Repl, [ In ] ) 除了正則表達式所有具體值被替代這點,它和 sub 函數完全一樣地執行,。
index( String1, String2 ) 在由 String1 參數指定的字符串(其中有出現 String2 指定的參數)中,返回位置,從 1 開始編號。如果 String2 參數不在 String1 參數中出現,則返回 0(零)。
length [(String)] 返回字符串的長度(字符形式)。默認整個記錄的長度($0 記錄變量)。
blength [(String)] 返回字符串的長度(以字節爲單位)。如果未給出 String 參數,則返回整個記錄的長度($0 記錄變量)。
substr( String, M, [ N ] ) 獲取子串,從M位置開始獲取N個字符,未指定N則到末尾。索引下標從1開始。
match( String, Ere ) 是否匹配。在 String 參數指定的字符串(Ere 參數指定的擴展正則表達式出現在其中)中返回位置(字符形式),從 1 開始編號,或如果 Ere 參數不出現,則返回 0(零)。RSTART 特殊變量設置爲返回值。RLENGTH 特殊變量設置爲匹配的字符串的長度,或如果未找到任何匹配,則設置爲 -1(負一)。
split( String, A, [Ere] ) 將字符串切割爲數組元素 A[1], A[2], . . ., A[n],並返回 n 變量的值。此分隔可以通過 Ere 參數指定的擴展正則表達式進行,默認使用FS分隔符。
tolower( String ) 轉小寫。
toupper( String ) 轉大寫。
sprintf(Format, Expr, Expr, . . . ) 獲取格式化字符串。

Ere都可以是正則表達式
格式符定義如下:
格式符 說明
%d 十進制有符號整數
%u 十進制無符號整數
%f 浮點數
%s 字符串
%c 單個字符
%p 指針的值
%e 指數形式的浮點數
%x %X 無符號以十六進制表示的整數
%o 無符號以八進制表示的整數
%g 自動選擇合適的表示法


如:
awk -F "s]id=" '{print $2}' db.log |awk -F "," '$1~/[0-9]+/ {print $1}'|sort -nu|wc -l

• [chengmo@centos5 ~]$ awk 'BEGIN{info="this is a test2010test!";gsub(/[0-9]+/,"!",info);print info}'  
this is a test!test!

• [wangsl@centos5 ~]$ awk 'BEGIN{info="this is a test2010test!";print index(info,"test")?"ok":"no found";}'   
ok

• [wangsl@centos5 ~]$ awk 'BEGIN{info="this is a test2010test!";print match(info,/[0-9]+/)?"ok":"no found";}'          
ok

[wangsl@centos5 ~]$ awk 'BEGIN{info="this is a test2010test!";print substr(info,4,10);}'                        
s is a tes
從第 4個 字符開始,截取10個長度字符串

• [chengmo@centos5 ~]$ awk 'BEGIN{info="this is a test";split(info,tA," ");print length(tA);for(k in tA){print k,tA[k];}}'
4
4 test
1 this
2 is
3 a

• [chengmo@centos5 ~]$ awk 'BEGIN{n1=124.113;n2=-1.224;n3=1.2345; printf("%.2f,%.2u,%.2g,%X,%o\n",n1,n2,n3,n1,n1);}'
124.11,18446744073709551615,1.2,7C,174

5.3 時間函數

函數 說明
mktime( YYYY MM DD HH MM SS[ DST]) 生成指定時間
strftime([format [, timestamp]]) 格式化時間輸出,將時間戳轉爲時間字符串 。具體格式,見下表.
systime() 得到時間戳,返回從1970年1月1日開始到當前時間(不計閏年)的整秒數

strftime日期和時間格式說明符
格式 描述
%a 星期幾的縮寫(Sun)
%A 星期幾的完整寫法(Sunday)
%b 月名的縮寫(Oct)
%B 月名的完整寫法(October)
%c 本地日期和時間
%d 十進制日期
%D 日期 08/20/99
%e 日期,如果只有一位會補上一個空格
%H 用十進制表示24小時格式的小時
%I 用十進制表示12小時格式的小時
%j 從1月1日起一年中的第幾天
%m 十進制表示的月份
%M 十進制表示的分鐘
%p 12小時表示法(AM/PM)
%S 十進制表示的秒
%U 十進制表示的一年中的第幾個星期(星期天作爲一個星期的開始)
%w 十進制表示的星期幾(星期天是0)
%W 十進制表示的一年中的第幾個星期(星期一作爲一個星期的開始)
%x 重新設置本地日期(08/20/99)
%X 重新設置本地時間(12:00:00)
%y 兩位數字表示的年(99)
%Y 當前月份
%Z 時區(PDT)
%% 百分號(%)


如:
• [chengmo@centos5 ~]$ awk 'BEGIN{tstamp=mktime("2001 01 01 12 12 12");print strftime("%c",tstamp);}'
2001年01月01日 星期一 12時12分12秒
 
• [chengmo@centos5 ~]$ awk 'BEGIN{tstamp1=mktime("2001 01 01 12 12 12");tstamp2=mktime("2001 02 01 0 0 0");print tstamp2-tstamp1;}'
2634468
 
[chengmo@centos5 ~]$ awk 'BEGIN{tstamp1=mktime("2001 01 01 12 12 12");tstamp2=systime();print tstamp2-tstamp1;}'
308201392


5.4 一般函數

函數 說明
close( Expression ) 用同一個帶字符串值的 Expression 參數來關閉由 print 或 printf 語句打開的或調用 getline 函數打開的文件或管道。如果文件或管道成功關閉,則返回 0;其它情況下返回非零值。如果打算寫一個文件,並稍後在同一個程序中讀取文件,則 close 語句是必需的。
system(Command ) 執行 Command 參數指定的命令,並返回退出狀態。等同於 system 子例程。
Expression | getline [ Variable ] 從來自 Expression 參數指定的命令的輸出中通過管道傳送的流中讀取一個輸入記錄,並將該記錄的值指定給 Variable 參數指定的變量。如果當前未打開將 Expression 參數的值作爲其命令名稱的流,則創建流。創建的流等同於調用 popen 子例程,此時 Command 參數取 Expression 參數的值且 Mode 參數設置爲一個是 r 的值。只要流保留打開且 Expression 參數求得同一個字符串,則對 getline 函數的每次後續調用讀取另一個記錄。如果未指定 Variable 參數,則 $0 記錄變量和 NF 特殊變量設置爲從流讀取的記錄。
getline [ Variable ] < Expression 從 Expression 參數指定的文件讀取輸入的下一個記錄,並將 Variable 參數指定的變量設置爲該記錄的值。只要流保留打開且 Expression 參數對同一個字符串求值,則對 getline 函數的每次後續調用讀取另一個記錄。如果未指定 Variable 參數,則 $0 記錄變量和 NF 特殊變量設置爲從流讀取的記錄。
getline [ Variable ] 將 Variable 參數指定的變量設置爲從當前輸入文件讀取的下一個輸入記錄。如果未指定 Variable 參數,則 $0 記錄變量設置爲該記錄的值,還將設置 NF、NR 和 FNR 特殊變量。


• [chengmo@centos5 ~]$ awk 'BEGIN{while("cat /etc/passwd"|getline){print $0;};close("/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

• [chengmo@centos5 ~]$ awk 'BEGIN{while(getline < "/etc/passwd"){print $0;};close("/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

• [chengmo@centos5 ~]$ awk 'BEGIN{print "Enter your name:";getline name;print name;}'

• [chengmo@centos5 ~]$ awk 'BEGIN{b=system("ls -al");print b;}'
total 42092
drwxr-xr-x 14 chengmo chengmo     4096 09-30 17:47 .
drwxr-xr-x 95 root   root       4096 10-08 14:01 ..

六.自定義函數

awk '
function max(a,b,c)
{
return a>b?a:b
}
{print max($1,$2)}' file

七.簡例


• #awk -F ':' '{print $1"\t"$7}' /etc/passwd

• #awk -F ':' 'BEGIN {print "name,shell"} {print $1","$7} END {print "blue,/bin/nosh"}' /etc/passwd

• # awk -F: '/^(root|web)/{print $7}' /etc/passwd
搜索/etc/passwd以root或web開頭的所有行,並顯示對應的shell

• # awk '/^root/,/^mysql/' test
打印以正則表達式root開頭的記錄到以正則表達式mysql開頭的記錄範圍內的所有記錄

• awk '$1~/1[0-9]/||$2>100 {print $1}' file 
顯示文件中第一個域匹配以1開頭兩位數的行


• #awk -F ':' '{print "filename:" FILENAME ",linenumber:" NR ",columns:" NF ",linecontent:"$0}' /etc/passwd
統計/etc/passwd:文件名,每行的行號,每行的列數,對應的完整行內容:


• #awk -F ':' '{printf("filename:%10s,linenumber:%s,columns:%s,linecontent:%s\n",FILENAME,NR,NF,$0)}' /etc/passwd
使用printf替代print,可以讓代碼更加簡潔,易讀

• awk '$1 * $2 >100 {print $1}' file 
搜索第一個域和第二個域之積大於100的行

• awk '{$1 == 'Chi' {$3 = 'China'; print}' file 
將Chi替換爲China

• awk 'BEGIN {system("echo \"Input your name:\\c\"");getline d;printf("Your name is %s!\n",d)}'

• awk -F ',' '{if($1>max){max=$1};} END{print max}' a.txt

統計最大數


• awk -F "," '{if(int(substr($NF,1,length($NF)-2))>=100){print $0}}' test.txt
統計最後一個字段時間大於100ms的記錄


• awk '{count++;print $0;} END{print "user count is ", count}' /etc/passwd
統計/etc/passwd的賬戶人數


• ls -l |awk 'BEGIN {size=0;} {size=size+$5;} END{print "[end]size is ", size}'
統計某個文件夾下的文件佔用的字節數


• ls -l |awk 'BEGIN {size=0;print "[start]size is ", size} {if($5!=4096){size=size+$5;}} END{print "[end]size is ", size/1024/1024,"M"}'
統計某個文件夾下的文件佔用的字節數,過濾4096大小的文件(一般都是文件夾):
awk中的循環語句同樣借鑑於C語言,支持if、while、do/while、for、break、continue,這些關鍵字的語義和C語言中的語義完全相同。



數組:數組的下標可以是數字和字母,數組的下標通常被稱爲關鍵字(key)。值和關鍵字都存儲在內部的一張針對key/value應用hash的表格裏。由於hash不是順序存儲,因此在顯示數組內容時會發現,它們並不是按照你預料的順序顯示出來的。數組和變量一樣,都是在使用時自動創建的,awk也同樣會自動判斷其存儲的是數字還是字符串。一般而言,awk中的數組用來從記錄中收集信息,可以用於計算總和、統計單詞以及跟蹤模板被匹配的次數等等。

• awk -F ':' 'BEGIN {count=0;} {name[count++] = $1;}; END{for (i = 0; i < NR; i++) print i, name[i]}' /etc/passwd
顯示/etc/passwd的賬戶

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章