awk命令(语言)
一、awk概述
1.為什么使用awk
awk?是一種程序語言.?它具有一般程序語言常見的功能.?因awk語言具有某些特點,?如?:?使用直譯器(Interpreter)不需先行編譯;?變量無類型之分(Typeless),?可使用文字當數組的下標(Associative Array)...等特色.?因此,?使用awk撰寫程序比起使用其它語言更簡潔便利且節省時間. awk還具有一些內建功能,?使得awk擅于處理具有數據行(Record),?字段(Field)型態的資料;?此外, awk內建有pipe的功能,?可將處理中的數據傳送給外部的?Shell命令加以處理,?再將Shell命令處理后的數據傳回awk程序,?這個特點也使得awk程序很容易使用系統資源.
由于awk具有上述特色,?在問題處理的過程中,?可輕易使用awk來撰寫一些小工具;?這些小工具并非用來解決整個大問題,它們只扮演解決個別問題過程的某些角色,?可藉由Shell所提供的pipe將數據按需要傳送給不同的小工具進行處理,?以解決整個大問題.?這種解題方式,?使得這些小工具可因不同需求而被重復組合及重用(reuse);?也可藉此方式來先行測試大程序原型的可行性與正確性,?將來若需要較高的執行速度時再用C語言來改寫.這是awk最常被應用之處.?若能常常如此處理問題,?讀者可以以更高的角度來思考抽象的問題,?而不會被拘泥于細節的部份.
2.如何工作
為便于解釋awk程序架構,?及有關術語(terminology),?先以一個員工薪資檔(emp.dat ),?來加以介紹.
cat emp.dat A125 Jenny 100 210 A341 Dan 110 215 P158 Max 130 209 P148 John 125 220 A123 Linda 95 210文件中各字段依次為?員工ID,?姓名,?薪資率,及?實際工時. ID中的第一碼為部門識別碼. "A","P"分別表示"組裝"及"包裝"部門.?本小節著重于說明awk程序的主要架構及工作原理,?并對一些重要的名詞輔以必要的解釋.?由這部分內容,?讀者可體會出awk語言的主要精神及awk與其它語程序言的差異處.?為便于說明,?以條列方式說明于后.
名詞定義:
a. 數據行?: awk從數據文件上讀取數據的基本單位.?以上列文件emp.dat為例, awk讀入的
第一筆數據行是?"A125 Jenny 100 210"
第二筆數據行是?"A341 Dan 110 215"
一般而言,?一個?數據行就相當于數據文件上的一行資料. (參考?:?內建變量"RS" )
b.字段(Field) :?為數據行上被分隔開的子字符串.
以數據行"A125 Jenny 100 210"為例,
第一欄?第二欄?第三欄?第四欄?"A125" "Jenny" 100 210
一般是以空白字符來分隔相鄰的字段. (?參考?:?內建變量"FS" )
附:內建字段變量
$0 # 一字符串, 其內容為目前 awk 所讀入的數據行. $1 # $0 上第一個字段的數據. $2 # $0 上第二個字段的數據....
當?awk?從數據文件中讀取一個數據行時, awk?會使用內建變量$0?予以記錄.每當?$0?被改動時?(例如?:?讀入新的數據行?或?自行變更?$0,...) awk?會立刻重新分析?$0?的字段情況,?并將?$0?上各字段的數據用?$1, $2, ..予以記錄.
c. Pattern :?awk?可接受許多不同型態的?Pattern.?一般常使用?"關系表達式"(Relational expression) 作為pattern.
例如:?x > 34?是一個?Pattern,?判斷變量?x?與?34?是否存在大于的關系.
附:常見pattern類型
BEGIN END >, <, >=, <=, ==, !=, ^指數 #關系運算符,與c基本一致 ~ (match) !~ (not match) /^[0-9]*$/ { print "This line is a integer !" } #正則表達式 FNR >= 23 && FNR <= 28 { print " " $0 } #混合pattern FNR == 23 , FNR == 28 { print " " $0 }#Pattern1 , Pattern2 遇到這種 Pattern, awk 會幫您設立一個 switch(或flag), Pattern1成立時打開 , Pattern2成立時關閉. 此例效果同上
d.?Actions :?Actions?是由許多awk指令構成.?而awk的指令與?C?語言中的指令十分類似.
例如?:?awk的I/O指令?: print, printf( ), getline... ,流程控制指令?: if(...){..} else{..}, while(...){...}...
附:常用指令(statement)
表達式 ( function calls, assignments..) print 表達式列表 printf( 格式化字符串, 表達式列表) if( 表達式 ) 語句 [else 語句] while( 表達式 ) 語句 do 語句 while( 表達式) for( 表達式; 表達式; 表達式) 語句 for( variable in array) 語句 delete #釋放數組中元素所占用的內存空間 break continue next #掠過其后所有指令,接著讀取下一個 Record exit [表達式] 語句e. 內建變量(Built-in Variables)
awk?提供了許多內建變量,?使用者于程序中可使用這些變量來取得相關信息.?常見的內建變量有?:
NF (Number of Fields) #為一整數, 其值表$0上所存在的字段數目. NR (Number of Records) #為一整數, 其值表awk已讀入的數據行數目. FNR #與 NR 功用類似. 不同的是awk每打開一個新的文件,FNR 便從 0 重新累計 FILENAME #awk正在處理的數據文件文件名. ARGC #表示命令行上除了選項 -F, -v, -f 及其所對應的參數之外的所有參數的個數.若將"awk程式"直接寫到命令列上, 則 ARGC 亦不將該"程式部分"列入計算. ARGV #ARGV數組用以記錄命令列上的參數. FS #欄位分隔字符. OFS #輸出時的欄位分隔字符. 預設值 " "(一個空格) ORS #輸出時數據行的分隔字符. 預設值 "\n"(換行) OFMT #數值資料的輸出格式. 預設值 "%.6g"(打印6位小數) RS #( Record Separator) : awk從文件上讀取資料時, 將根據 RS 的定義把資料切割成許多Records,而awk一次僅讀入一個Record,以進行處理.?f. 數組
awk程序中允許使用字符串當做數組的下標(index).?利用這個特色十分有助于資料統計工作.(使用字符串當下標的數組稱為Associative Array).?使用數組前不須宣告數組名及其大小.
?g.內建函數
# 以下為字符串函數 index( 原字串, 找尋的子字串 ) #若原字串中含有欲找尋的子字串,則返回該子字串在原字串中第一次出現的位置,若未曾出現該子字串則返回0. length( 字串 ) #返回該字串的長度. match( 原字串, 用以找尋比對的正則表達式 ) #awk會在原字串中找尋合乎正則表達式的子字串. 若合乎條件的子字串有多個, 則以原字串中最左方的子字串為準. awk找到該字串后會依此字串為依據進行下列動作: 設定awk內建變量 RSTART, RLENGTH :RSTART = 合條件的子字串在原字串中的位置.(未找到0)RLENGTH = 合條件的子字串長度.(未找到-1) 返回 RSTART 之值. split( 原字串, 數組名稱, 分隔字符 ) #awk將依所指定的分隔字符(field separator)來分隔原字串成一個個的欄位(field),并以指定的數組(下標從1開始)記錄各個被分隔的欄位. sprintf(格式字符串, 項1, 項2, ...) sub( 比對用的正則表達式, 將替換的新字串, 原字串 ) #將原字串中第一個(最左邊)合乎所指定的正則表達式的子字串改以新字串取代. 第二個參數"將替換的新字串"中可用"&"來代表"合於條件的子字串" gsub( 比對用的正則表達式, 將替換的新字串, 原字串 ) #這個函數與 sub()一樣,同樣是進行字串取代的函數. 唯一不同點 gsub()會取代所有合條件的子字串. gsub()會返回被取代的子字串個數. substr( 字串,起始位置 [,長度] ): #返回從起始位置起,指定長度的子字串. 若未指定長度,則返回起始位置到字串末尾的子字串.# 以下為數學函數 int(x) #返回x的整數部分(去掉小數). sqrt(x) #返回x的平方根. exp(x) # 將返回e的x次方. log(x) #將返回x以e為底的對數值. sin(x) # x 須以弧度為單位,sin(x)將返回x的sin函數值. cos(x) # x 須以弧度為單位,cos(x)將返回x的cos函數值 atan2(y,x) # 返回 y/x 的tan反函數之值,返回值系以弧度為單位. rand() # 返回介于 0與1之間的(近似)隨機數值; 0 < rand()<1. srand([x]) # 指定以x為rand( )函數起始的種子.h. 工作流程
執行awk時,?它會反復進行下列四步驟.
awk會自動重復進行上述4個步驟,?使用者不須于程序中編寫這個循環?(Loop).
?i.使用系統資源
awk?提供與?UNIX?用法近似的?pipe,?其記號亦為?"|".?其用法及含意如下?:
[a. 語法] awk output指令 | "Shell命令" #( 如 : print $1,$2 | "sort -k 1" ) [b. 語法] "Shell命令" | awk input指令 #( 如 : "ls" | getline)在?a?語法中,??awk所輸出的數據將轉送往?Shell ,?由?Shell?的命令進行處理.?以上例而言, print?所輸出的數據將經由?Shell?命令?"sort -k 1"?排序后再送往屏幕(stdout).
上例中, "print$1, $2"?可能反復執行很多次,?其輸出的結果將先暫存于?pipe?中,等到該程序結束時,?才會一并進行?"sort -k 1".?"sort -k 1"?的執行次數是一次.?
在?b?語法中, awk將先調用?Shell?命令.?其執行結果將通過?pipe?送入awk程序, 就上例而言, awk先讓?Shell?執行?"ls", Shell?執行后將結果存于?pipe, awk指令?getline再從pipe?中讀取數據.
使用本語法時應留心:?以上例而言,awk "立刻"調用?Shell?來執行?"ls",?執行次數是一次.?getline?則可能執行多次(若pipe中存在多行數據).
除上列?a, b 兩種語法外, awk程序中其它地方如出現像?"date", "clear", "ls"...?這樣的字符串, awk只把它當成一般字符串處理.?
?
二、格式及使用(不同版本awk,nawk,mawk,gawk)
Pattern1 { Actions1 }
Pattern2 { Actions2 }
......
awk?會先判斷?(Evaluate)?該?Pattern?的值,?若?Pattern?判斷后的值為true (或不為0的數字,或不是空的字符串),?則?awk將執行該?Pattern?所對應的?Actions.?反之,?若?Pattern?之值不為?true,?則awk將不執行該?Pattern所對應的?Actions.
例如?:?若awk程序中有下列兩指令
50 > 23 {print "Hello! The word!!" } "banana" ~ /123/ { print "Good morning !" }awk會先判斷?50 >23?是否成立.?因為該式成立,?所以awk將印出"Hello! The word!!".?而另一?Pattern?為?"banana" ~/123/,?因為"banana"?內未含有任何子字符串可?match /123/,?該?Pattern?之值為false,?故awk將不會印出?"Good morning !"
有時語法?Pattern { Actions }中, Pattern?部分被省略,只剩?{Actions}.?這種情形表示?"無條件執行這個?Actions".
3.執行方式(三種)
例:打印出文件?today_rpt1?及?today_rpt2?的內容
awk '{print}' today_rpt1 today_rpt2 #方式一,直接寫在 Shell 的命令行上, 這種方式僅適合較短的awk程序. awk -f mydump.awk today_rpt1 today_rpt2 #方式二,將awk程序寫入到文件中 #!/bin/sh #方式三,建立 shell 腳本 # 注意 awk 與 ' 之間須有空白隔開 awk '{print}' $*注:awk程序中一律以"括住字符串或字符,?而不使用?' ,?以免與?Shell?混淆.
?
三、使用舉例
1.打印文件中指定的字段數據并加以計算.?
以文件?emp.dat?為例,?計算每人應發工資并打印報表.
awk '{ print $2, $3 * $4 }' emp.dat awk '{ printf("%-6s Work hours: %3d Pay: %5d\n", $2, $3, $3* $4) }' emp.dat注:Pattern?部分被省略,?表無任何限制條件.?print為awk所提供的輸出指令,?會將數據輸出到stdout(屏幕).?print?的參數間彼此以?"," (逗號)?隔開,?印出數據時彼此間會以空白隔開. (參考:內建變量OFS).?awk中也提供與?C?語言中類似用法的?printf()?函數.?使用該函數可進一步控制數據的輸出格式.
2.選擇符合指定條件的記錄.?
組裝部門員工調薪5%,(組裝部門員工之ID以"A"開頭).?所有員工最后之薪資率若仍低于100,?則以100計.
awk '$1 ~ /^A.*/ { $3 *= 1.05 } $3<100 { $3 = 100 } { printf("%s %8s %d\n", $1, $2, $3)}' emp.dat3.數組及循環的使用
首先建立一個數據文件,?并取名為?reg.dat.?此為一學生注冊的資料文件;?第一欄為學生姓名,?其后為該生所修課程.
cat reg.dat Mary O.S. Arch. Discrete Steve D.S. Algorithm Arch. Wang Discrete Graphics O.S. Lisa Graphics A.I. Lily Discrete Algorithm統計各科修課人數,并印出結果:
cat course.awk {for( i=2; i <= NF; i++) Number[$i]++ } END{for(course in Number) printf("%10s %d\n", course, Number[course] ) } awk -f course.awk reg.dat? Graphics 2O.S. 2Discrete 3A.I. 1D.S. 1Arch. 2Algorithm 2注:數組默認值為 0.?END?成立(其值為true)的條件是: "awk處理完所有數據,?即將離開程序時?".?唯有當awk讀完所有數據時,?該Actions才會被執行?(?注意,?不管數據行有多少筆, END僅在最后才成立,?故該Actions僅被執行一次.)?BEGIN?與?END?有點類似,?是awk中另一個保留的Pattern.
4.使用shell命令
awk程序中允許呼叫Shell指令.?并提供管道解決awk與系統間數據傳遞的問題.?所以awk很容易使用系統資源.?讀者可利用這個特點來編寫某些適用的系統工具.
寫一個?awk?程序(count.awk)來打印出在線用戶數.
BEGIN {while ( "who" | getline ) n++print n }awk -f count.awk
注:awk?程序并不一定要處理數據文件.?以本例而言,?僅輸入程序文件count.awk,?未輸入任何數據文件.
awk提供另一個調用Shell命令的方法,?即使用awk函數system("shell命令"),如:
BEGIN {system("date > date.dat")getline < "date.dat"print "Today is ", $2, $3 }但使用?system( "shell?命令" )?時, awk無法直接將執行中的部分數據輸出給Shell?命令.?且?Shell?命令執行的結果也無法直接輸入到awk中.
5.綜合程序
本節將示范一個統計上班到達時間及遲到次數的程序.?該程序每日被執行時將讀入兩個文件:員工當日到班時間的數據文件?(如下列之?arr.dat) 和?存放員工當月遲到累計次數的文件.
某公司其員工到勤時間檔如下,?取名為?arr.dat.?文件中第一欄為員工代號,?第二欄為到達時間.?本范例中,?將使用該文件為數據文件.?
1034 7:26 1025 7:27 1101 7:32 1006 7:45 1012 7:46 1028 7:49 1051 7:51 1029 7:57 1042 7:59 1008 8:01 1052 8:05 1005 8:12a.在到班數據文件?arr.dat?之前增加一行標題,?并產生報表輸出到文件?today_rpt1中
BEGIN { file = "today_rpt1"print " ID Number Arrival Time" > fileprint "===========================" > file } { printf(" %s %s\n", $1, $2) > file } ID Number Arrival Time ===========================1034 7:261025 7:271101 7:321006 7:451012 7:461028 7:491051 7:511029 7:571042 7:591008 8:011052 8:051005 8:12注:awk程序中,?文件名稱?file?的前后須以" (雙引號)括住,?表示為一字符串常量.?若未以"括住,?則?today_rpt1?將被awk解釋為一個變量名稱.?本程序中若使用?">"?將數據重導到?today_rpt1, awk?第一次執行該指令時會產生一個新文件?today_rpt1,?其后再執行該指令時則把數據追加到today_rpt1文件末,?并非每執行一次就重開一個新文件.?若采用">>"其差異僅在第一次執行該指令時,?若已存在today_rpt1則?awk?將直接把數據?append?在原文件末尾.?這一點,?與UNIX中的用法不同.
?b.將數據按員工ID排序后再輸出到文件?today_rpt2 ,?并于表頭附加執行時的日期.
BEGIN {file = "today_rpt2""date" | getline # Shell 執行 "date", getline 取得結果并以$0記錄print " Today is " , $2, $3 > fileprint "=========================" > fileprint " ID Number Arrival Time" > fileclose( file ) } { printf(" %s %s\n", $1 ,$2 ) | "sort -k 1 >> today_rpt2" }注:awk?的輸入指令?getline,?每次讀取一列數據.?若getline之后未接任何變量,?則所讀入之資料將以$0?記錄,?否則以所指定的變量儲存之.?getline?一次讀取一行資料,?若讀取成功則return 1,若讀取失敗則return -1,?若遇到文件結束(EOF),?則return 0.
本程序中?printf()?指令會被執行多次,?但讀者不用擔心數據被重復sort了12次.?當awk結束該程序時才會?close?這個?pipe ,?此時才將這12行數據一次送往系統,并呼叫?"sort -k 1 >> today_rpt2"?處理之.
?c.若八點為上班時間,?請加注?"*"于遲到記錄之前,?并計算平均上班時間.?
#!/bin/sh awk ' BEGIN {FS= "[ \t:]+" #改變字段切割的方式,可匹配多次file = "today_rpt3""date" | getline print " Today is " ,$2, $3 > fileprint "=========================" > fileprint " ID Number Arrival Time" > fileclose( file ) } {#已更改字段切割方式, $2表到達小時數, $3表分鐘數arrival = HM_to_M($2, $3)printf(" %s %s:%s %s\n", $1, $2, $3, arrival > 480 ? "*": " " ) | "sort -k 1 >> today_rpt3"total += arrival } END {close("today_rpt3")close("sort -k 1 >> today_rpt3")printf(" Average arrival time : %d:%d\n", total/NR/60, (total/NR)%60) >> "today_rpt3" } function HM_to_M( hour, min ){return hour * 60 + min } ' $*注:字段分隔字符?FS (field seperator)?是awk的內建變量,其默認值是空白及tab. awk每次切割字段時都會先參考FS?的內容.?awk?中亦允許使用者自定函數.?函數定義方式請參考本程序, function?為?awk?的保留字.
指令?close( "sort -k 1 >> today_rpt3" ),?其意思為關閉程序中置于?"sort -k 1 >> today_rpt3 "?之前的?Pipe ,?并立刻調用?Shell?來執行"sort -k 1 >> today_rpt3". (若未執行這指令, awk必須于結束該程序時才會進行上述動作;則這12筆sort后的數據將被追加到文件?today_rpt3?中?"Average arrival time : ..."?的后方)
因為?Shell?排序后的數據也要寫到?today_rpt3,?所以awk必須先關閉使用中的today_rpt3?以使?Shell?正確將排序后的數據追加?today_rpt3.?否則2個不同的?process?同時打開一個文件進行輸出將會產生不可預期的結果.?
?d.從文件中讀取當月遲到次數,?并根據當日出勤狀況更新遲到累計數.(按不同的月份累計于不同的文件)
cat 09月late.dat 1012 0 1006 1 1052 2 1034 0 1005 0 1029 2 1042 0 1051 0 1008 0 1101 0 1025 1 1028 0 #!/bin/sh awk ' BEGIN {Sys_Sort = "sort -k 1 >> today_rpt4"file = "today_rpt4"FS = "[ \t:]+""date" | getlineprint " Today is " , $2, $3 > fileprint "=========================" > fileprint " ID Number Arrival Time" > fileclose( file )# 從文件按中讀取遲到數據, 并用數組cnt[ ]記錄. 數組cnt[ ]中以# 員工代號為下標, 所對應的值為該員工之遲到次數.late_file = $2"late.dat"while( getline < late_file >0 ) cnt[$1] = $2close( late_file ) } {# 已更改字段切割方式, $2表小時數,$3表分鐘數arrival = HM_to_M($2, $3)if( arrival > 480 ){mark = "*" # 若當天遲到,應再增加其遲到次數, 且令mark 為"*".cnt[$1]++ }else mark = " "# message 用以顯示該員工的遲到累計數, 若未曾遲到message為空字符串message = cnt[$1] ? cnt[$1] " times" : ""printf("%s %2d:%2d %5s %s\n", $1, $2, $3, mark, message ) | Sys_Sorttotal += arrival } END {close( file )close( Sys_Sort )printf(" Average arrival time : %d:%d\n", total/NR/60, (total/NR)%60 ) >> file#將數組cnt[ ]中新的遲到數據寫回文件中for( any in cnt )print any, cnt[any] > late_file } function HM_to_M( hour, min ){return hour*60 + min } ' $* Today is 04月 10日 =========================ID Number Arrival Time 1005 8:12 * 1 times 1006 7:45 1008 8: 1 * 1 times 1012 7:46 1025 7:27 1028 7:49 1029 7:57 1034 7:26 1042 7:59 1051 7:51 1052 8: 5 * 1 times 1101 7:32 Average arrival time : 7:496.處理多行數據(改變RS)
RS?的默認值是?"\n",?故平常awk中一行數據就是一個?Record.?當?RS = ""?時:連續的空白行僅被視成一個單一的Record Saparator. ?且awk會略過文件頭或文件尾的空白行.
張長弓 GNUPLOT 入門吳國強 Latex 簡介 VAST-2 使用手冊 mathematic 入門李小華 awk Tutorial Guide Regular Expression #!/bin/sh awk ' BEGIN {RS = ""FS = "\n" split( "一. 二. 三. 四. 五. 六. 七. 八. 九.", order, " " ) } {printf("\n%s 報告人 : %s \n", order[NR], $1)for( i=2; i <= NF; i++) printf(" %d. %s\n", i-1, $i) } ' $* 一. 報告人 : 張長弓 1. GNUPLOT 入門二. 報告人 : 吳國強 1. Latex 簡介2. VAST-2 使用手冊3. mathematic 入門三. 報告人 : 李小華 1. awk Tutorial Guide2. Regular Expression7.讀取命令行參數
#!/bin/sh awk ' BEGIN { for( i=0; i<ARGC ; i++)print ARGV[i] # 依次印出awk所記錄的參數 } ' "$@"注:ARGC :?為一整數.?代表命令行上,?除了選項-v, -f?及其對應的參數之外所有參數的數目.?ARGV[] 為一字符串數組. ARGV[0],ARGV[1],...ARGV[ARGC-1], 分別代表命令行上相對應的參數.
8.與用戶交互
apple 蘋果 orange 柳橙 banana 香蕉 pear 梨子 starfruit 楊桃 bellfruit 蓮霧 kiwi 奇異果 pineapple 菠蘿 watermelon 西瓜 #!/bin/sh awk ' BEGIN {while( getline < ARGV[1] ){ #由指定的文件中讀取測驗數據English[++n] = $1 # 最后, n 將表示題目之題數Chinese[n] = $2}ARGV[1] = "-" # "-"表示由stdin(鍵盤輸入)srand() # 以系統時間為隨機數啟始的種子question() #產生考題 }{# awk自動讀入由鍵盤上輸入的數據(使用者回答的答案)if($1 != English[ind] )print "Try again!"else{print "\nYou are right !! Press Enter to Continue --- "getlinequestion()} } function question(){ind = int(rand() * n) + 1 #以隨機數選取考題system("clear")print "Press ""ctrl-d"" to exit"printf("\n%s ", Chinese[ind] " 的英文生字是: ") } ' $*注:awk的數學函數中提供兩個與隨機數有關的函數.?srand( ) 以當前的系統時間作為隨機數的種子.?rand( )?返回介于?0與1之間的(近似)隨機數值.
9.編寫遞歸程序
awk?中除了函數的參數列(Argument List)上的參數(Arguments)外,所有變量不管于何處出現,全被視為全局變量.?其生命持續至程序結束——該變量不論?function外或?function內皆可使用,只要變量名稱相同所使用的就是同一個變量,直到程序結束.?此特性優劣參半,?最大的壞處是式中的變量不易被保護,?特別是遞歸調用本身,?執行子函數時會破壞父函數內的變量.
一個變通的方法是:?在函數的參數列中虛列一些參數.?函數執行中使用這些虛列的參數來記錄不想被破壞的數據,如此執行子函數時就不會破壞到這些數據.?此外awk?并不會檢查調用函數時所傳遞的參數個數是否一致.?$0, $1,.., NF, NR..也都是?global variable,?讀者于遞歸函數中若有使用這些內建變量,?也應另外設立一些局部變量來保存,以免被破壞.
以下是一個常見的遞歸調用范例.?它要求使用者輸入一串元素(各元素間用空白隔開)?然后印出這些元素所有可能的排列.
#!/bin/sh awk ' BEGIN {print "請輸入排列的元素,各元素間請用空白隔開"getlinepermutation($0, "")printf("\n共 %d 種排列方式\n", counter) } function permutation( main_lst, buffer, new_main_lst, nf, i, j ) {$0 = main_lst # 把main_lst指定給$0之后awk將自動進行字段分割.nf = NF # 故可用 NF 表示 main_lst 上存在的元素個數.# BASE CASE : 當main_lst只有一個元素時.if( nf == 1){#buffer的內容再加上main_lst就是完成一次排列的結果 print buffer main_lst counter++return}# General Case : 每次從 main_lst 中取出一個元素放到buffer中# 再用 main_lst 中剩下的元素 (new_main_lst) 往下進行排列else for( i=1; i<=nf ;i++){$0 = main_lst # $0為全局變量已被破壞, 故重新把main_lst賦給$0,令awk再做一次字段分割new_main_lst = ""for(j=1; j<=nf; j++) # 連接 new_main_lstif( j != i ) new_main_lst = new_main_lst " " $jpermutation( new_main_lst, buffer " " $i )} } ' "$@"注:?awk?中欲將字符串concatenation(連接)時,?直接將兩字符串并置即可(Implicit Operator).?awk使用者所編寫的函數可再重用,?并不需要每個awk式中都重新編寫.?將函數部分單獨編寫于一文件中,?當需要用到該函數時再以下列方式include進來
awk -f 函數文件名 -f awk主程序文件名 數據文件文件名?
四、實戰
1.去除空行
abc awk '{ if ($0 != "") rs=rs$0; } END { print rs }' awk ' {if ($0 != ""){if (FNR != 1)rs=rs"\n";rs=rs$0;} } END{ print rs; } '?
整理自:http://kb.cnblogs.com/a/1310146/? ?http://man.lupaworld.com/content/manage/ringkee/awk.htm
轉載于:https://www.cnblogs.com/xiangzi888/archive/2012/04/10/2440009.html
總結
- 上一篇: MYSQL delete语句不支持别名?
- 下一篇: Chart Share