1. 程式人生 > >linux 下awk 的使用

linux 下awk 的使用

因為工作需要,自己接觸了並熟悉awk。awk 是一個非常優秀的文字處理工具,用它你可以處理很多問題。
標準的格式: awk [ -F re] [parameter...] ['pattern {action}' ] [-f progfile][in_file...]
在介紹awk使用之前先介紹一下內建變數、函式相關知識:

內建變數:

$0當前記錄行,代表一行記錄
$1~$n當前記錄的第n個欄位,欄位間由FS分隔
ARGC         命令列引數個數 (指令碼部分使用)
ARGV         命令列引數排列 (指令碼部分使用 ,其就是一個數組)
ENVIRON      支援佇列中系統環境變數的使用
FILENAME     awk瀏覽的檔名 
FNR          瀏覽檔案的記錄數 
FS           設定輸入域分隔符,等價於命令列 -F選項 
NF           瀏覽記錄的域的個數 
NR           已讀的記錄數 
OFS          輸出域分隔符 
ORS          輸出記錄分隔符 
RS           控制記錄分隔符
BEGIN/END   BEGIN和END的作用是給程式賦予初始狀態和在程式結束之後執行一些掃尾的工作。任何在BEGIN之後列出的操作(在{}內)將在Unix awk開始掃描輸入之前執行,而END之後列出的操作將在掃描完全部的輸入之後執行。因此,通常使用BEGIN來顯示變數和預置(初始化)變數,使用END來輸出最終結果。

內建函式:

split(string, array [, fieldsep [, seps ] ])
功能:將string表示的字串以fieldsep為分隔符進行分隔,並將分隔後的結果儲存至array為名的陣列中;陣列下標為從0開始的序列;
length([string])
功能:返回string字串中字元的個數
substr(string, start [, length])
功能:取string字串中的子串,從start開始,取length個;start從1開始計數
system(command)
功能:執行系統command並將結果返回至awk命令
systime()
功能:取系統當前時間
tolower(s)
功能:將s中的所有字母轉為小寫
toupper(s)
功能:將s中的所有字母轉為大寫

print和printf

awk中提供了print和printf兩個列印輸出的函式:print函式的引數可以是變數、數值或者字串。字串必須用雙引號引用,引數用逗號分隔;printf函式,的用法和c語言中printf基本相似,可以格式化字串,輸出複雜時,printf更加好用,具體格式如下:
%c:   顯示字元的ASCII碼
%d,%i :   顯示十進位制整數
%e,%E:   科學計數法數值顯示
%f :     顯示為浮點數
%g,%G:   以科學數法或浮點形式顯示數值
%s:  顯示字串
%u:  無符號整數
%%:  顯示%號自身,相當於轉義
 
下面我來介紹awk:首先,awk 支援 if-else / while / do-while / for 等這些操作。使用模式有兩種,一種是直接操作檔案,另一種是使用指令碼處理。

(1)簡單命令:可以做一些簡單的操作
awk -F '分隔符'  '{處理過程}' filename 
例:awk -F ',' '{print $2}' awk.txt 
分隔符為 ','  
輸出$2(輸出檔案第二列資料);處理過程類似C語言處理
awk.txt 檔名
(2)複雜命令:可以做一下邏輯比較複雜的操作
awk -F '分隔符'  'BEGIN{初始化} {處理過程} END{結束}' filename
例:awk -F ',' 'BEGIN{print "start ...";sum=0;num=0} {sum+=$2;num++} END{print "end...";print "Average = ",sum/num}' awk.txt  
BEGIN  在讀取檔案檔案第一行之前執行,就好像C++的建構函式
end    在讀取檔案檔案最後一行之後執行,就好像C++的解構函式
這個適合用於處理平均值之類的資料 ,num 也可以使用 NR(已讀的記錄數)替換
(3)高階命令:可以把多個檔案放在一起處理 
awk -F '分隔符'  'BEGIN{初始化} {處理過程} END{結束}' filename1 filename2 。。。
例:awk -F ',' 'BEGIN{print "start ...";} NR==FNR{a[$3]=$2;} NR!=FNR && a[$4] {printf"%s,%s,%s" ,$1,$4,a[$4]} END{print "end...";print "Average = "}' awk1.txt  awk1.txt 
NR :已讀的記錄數
FNR :瀏覽檔案的記錄數 ,讀取第二個檔案的時候就重置了
NR==FNR 表示讀取第一個檔案 
條件正確執行:a[$3]=$2  ==> 以第一個檔案的$3欄位為下標建立一個數組,這個元素的值為$2 
NR!=FNR(不成立時 表示讀取第二個檔案)
a[$4] :表示第二個檔案的$4 欄位作為下標讀取a[]陣列中的值
&&與運算 ,以上兩個條件成立則執行後面的處理
(4)指令碼處理檔案
awk -F '分隔符' -f  指令碼檔案   傳入的檔案(引數的作用)
awk -F ',' -f  script.awk   filename1 filename2 filename3 。。。
script.awk 為指令碼檔案,在指令碼檔案中可以進行多複雜的操作:
如下:
######################################################
function trimcite(v) {vlen=length(v); return substr(v, 2, vlen-2)}    #自定義函式
BEGIN {printf("start...\n")} 
FILENAME==ARGV[1] && FNR > 1 {name=sprintf("%s%s", $2, $3); map[name]=$1}     
FILENAME==ARGV[2] && FNR > 2 {name=sprintf("%s%s", trimcite($2), trimcite($4)); value=map[name]; map_id_ip[$2]=value}
FILENAME==ARGV[3] && FNR > 2 {id=trimcite($3); value=map_id_ip[id];if(map_id_ip[id]) {printf("%s,%s,%s\n", $1, $2,value)}}
END{print {printf("end...\n")} 

######################################################

(5)awk 根據欄位進行去重操作

awk -F '分隔符'  '{處理過程}' filename  

例:awk -F ',' '!a[$2]++{print}' awk.txt 

a[$2]初值為0 ,!a[$2]對應的值為1,則輸出整行值;第一次輸出以後a[$2] 對應的值為1,2.。。。,!a[$2]對應的值為0,則無輸出。

最後。。。 awk 可以配合sed使用。