2010年1月22日 星期五

Awk Script 語言

指令行語法

awk 的指令行啟動方式有兩種:

awk [options] 'script' var=value file(s)
awk [options] -f scriptfile var=value file(s)


可在指令行直接使用 script,或是將 script 放入檔案中以 scriptfile 形式執行。變數可以在指令行中指定其值。值可以是字元字串或是 shell 變數($name)或是指令替代('cmd'),但所指定的變數值只有在讀入一行輸入以後才生效(也就是在 BEGIN 之後)。awk 可以一次處理多個檔案。若不指定檔案,或是用 - 來代替檔名,則從標準輸入取得輸入的資料。

可用的 options 如下:

-Fc              將欄分隔字元設定為 c。這和系統變數 FS 的設定作用相同。Nawk 中的 c 可以是一個常規表示式 (regular expression)。每行輸入(或是記錄的輸入)都由分隔符號(預設為空白字元)隔成一個一個欄位。你可以透過 $1, $2,..., $n 等變數來存取各個欄位的值。$0 則代表整筆記錄(或是這一整行)。

-v var=value              value 的值指定給變數 var。這可以在 script 開始執行前就指定一個變數的值(僅 nawk 可使用)。

例如,如果要將前三欄分別印在不同的行中,指令如下:

              awk -F: '{print $1; print $2; print $3}' /etc/passwd

詳見本章之後的 "pattern 和程序 " 一節




awk 概說

awk 主要是以樣式比對來處理檔案,尤其是用於資料庫中。後來推出 nawk,加入了不少新功能,而目前 SVR4 的系統上都已加上 nawk 了,不過 awk 還是可以使用(實際上是一個連到oawk 的連結)。下一版的 System V 中,nawk 將會取代 awk。(還有一個由 GNU 出的 gawk,也包括了所有 nawk 的功能。)


awk 原有功能如下:

. 純文字檔案可視為一個很大的文字資料庫,每個字都是一個欄位。
. 利用變數來更動資料庫
. 進行數學或是字串運算
. 可使用迴圈或是條件式來控制流程
. 輸出可以格式化

nawk 的新功能如下:

. 定義新的函式
. script 中執行 UNIX 指令
. 處理 UNIX 指令的輸出
. 指令行參數處理較容易
. 多重輸入


pattern 和程序

awk script pattern 和程序(procedure)組成

pattern {procedure}

若不加上 pattern,則 [procedure] 對所有的行作用。若不加上 [procedure],則列出符合 pattern 的行。


-----------------------------------------------------------------------------

Pattern

pattern 可以是下列任一種型態:

/regular expression/
relational expression
pattern-matching expression
BEGIN
END

. expression 可以是引用字串或是數字、運算子、函式、變數或是任何定義過的系統變數。

. regular expression 所使用的中介字元在第六章有詳細說明。

. ^$ 兩個符號分別代表一個欄位的開頭和結尾,而非一行的開頭和結尾。

. 比較式所使用的運算子在後面 " 運算子 " 一節有更詳細的說明。可以拿數字或是自串來做比較。如 $2>$1 會印出第二欄大於第一欄的行。

. pattern matching 使用 ~ !~ 來表示符合和不符合。詳見 " 運算子 " 一節

. BEGIN 可以指定讀入資料之前所執行的程序。(通常在此定義全域變數)

. END 可指定在讀入最後一行資料以後所執行的程序。

除了 BEGIN END 以外。pattern 都可以用 ||or)、&&and)、!not)連起來。若要一次指定一整個範圍,也可以用

pattern, pattern

的形式。


-----------------------------------------------------------------------------

程序(Procedure

程序的結構,最外層是 {},中間可以有指令,函式或是指定變數,彼此以換行字元或是分號分開。指令分為下面四類:

. 指定變數或是陣列
. 列印指令
. 內建指令
. 流程控制

-----------------------------------------------------------------------------

簡單的例子

1. 印出每一行的第一欄:

              { print $1 }

2. 印出所有有 pattern 的行:

              /pattern/

3. 將所有含有 pattern 的行的第一欄印出:

              /pattern/{ print $1 }

4. 選擇超過兩欄的行:

              NF > 2

5. 將輸入的資料當做一些行的集合:

              BEGIN { FS = "\n"; RS = "" }
             

6. 將第一欄為 URGENT 的行取出後,將其第二第三欄以相反順序印出:

              $1 ~ /URGENT/ { print $3, $2 }

7. 印出找到 pattern 的次數:

              /pattern/ { ++x }
              END { print x }

8. 將第二欄的數字加總後印出:

              {total += $2 };
              END { print "column total is", total}

9. 印出少於 20 個字元的行:

              length < 20

10. 印出以 Name 開頭,而且內容恰有七欄的行:

              NF == 7 && /^Name:/

11. 將所有欄的順序顛倒:
              { for (i = NF; i >= 1; i--) print $I }

Awk 系統變數


<<<<<< 排版請注意 ,左兩欄不翻 >>>>>>>>>>>>>

版本               變數               說明
awk                                                        目前檔名
                                                        欄位分隔字元(預設為空白字元)
                                                        目前行中的欄位數
                                                        目前的行數
                                                        輸出的欄位分隔字元
                                                        輸出的行分隔字元
                                                        行分隔字元
                                                        整個輸入的資料
                                                        資料中的第 n 欄,欄位以 FS 分開

nawk                                          指令行的參數個數
                                                        儲存指令行參數的陣列
                                                        NR 類似,但指目前檔案
                                                        數字輸出格式
                                                        match 指令執行後所找到的字串起點
                                                        match 指令所找到的字串長度
                                               陣列足碼的分隔字元(預設為 \034

gawk                                          環境變數陣列
                                                        不管大小寫


----------------------------------------------------------------

運算子

下列為 awk 中所使用的運算子,以優先順序排列:

符號                  意義
= += -= *= /= %= ^=                            指定值
?:                            C 的條件式(gawk nawk
||                            邏輯 OR
&&                            邏輯 AND
~ !~              符合或不符合該 常規表示式
< <= > >= != ==                            關係運算子
(blank)              串接
+ -                            加減
* / %              乘除和取餘數
+ - !              正號負號與 NOT
^                            指數
++ --              1 或減 1,可用後置或前置式
$                            欄位符號


----------------------------------------------------------------


變數和陣列

若要指定變數的值,可用下面的形式:

var = value

比如 FS = ","。所指定的值可以包含 +-*/ %


要定義陣列則需使用 split 函式,或是在指定變數值時建立。+++=-= 的用法和 C 語言一樣,可以用來取用陣列。陣列元素可以用足碼取用,如 array[1], ..., array[n],或是使用其名稱。比如,若要紀錄某個 pattern 出現的次數,可用下面的指令:


<<<<  code  >>>>>>>


指令分類列表

awk 指令可分為下列幾類

<<<<<< 排版請注意 ,中間的指令不用翻 >>>>>

數學運算               字串功能               流程控制               輸出入               其它



<<<<<< 下面還有兩小行字 >>>>>
* 用於 nawk
+ 用於 gawk


p11-7


指令解說

指令解說中有 N 者,為 nawk 專用指令,有 G 者為 gawk 專用指令,若無指定,則各版本的 awk 皆可使用。


--------------------------------------

atan2(y,x)

傳回 y/x arc-tangent 值,單位為弧度。{N}


--------------------------------------
break

while 或是 for 迴圈跳出。


--------------------------------------
close(filename-expr)
close(command-expr)

大部份的 awk 一次只能開十個檔案外加一個 pipe。所以 nawk 提供了 close 指令來關閉一些檔案(或是 pipe)。其中 expr 為開啟該檔案或是 pipe 的運算式。{N}


--------------------------------------
continue

直接繼續下一次 while for 的迴圈。


--------------------------------------
cos(x)

傳回 x cosine 值,單位為弧度。


--------------------------------------
delete(array[element])

將陣列 array 中的 element 元素刪除。{N}


--------------------------------------
do
body
while(expr)

先執行 body 中的指令,然後檢查 expr,若 expr 成立,則回到 do 然後再執行 body,如此周而復始。{N}


--------------------------------------
exit

不繼續執行下去,直接去執行 END 的程序然後跳出。


--------------------------------------
exp(arg)

傳回 e arg 次方(log的反函數)。


--------------------------------------
for(i=lower; i<=upper; i++)
command

i 之值介於 lower upper 之間時,執行 command,然後將 i 1。若一次執行多個指令則需加上 {}<= 可用任何關係運算子取代。而 i 可以用 ++ -- 來遞增或遞減。


--------------------------------------
function name(parameter-list){
statements
}

name 定義為使用者的函式,傳入參數 parameter-list,然後執行 awk 指令 statements


--------------------------------------
getline [var][

command | getline [var]

讀取下一行輸入。原本的 awk 並不能一次開很多個輸入流。第一種形式從檔案中讀入資料,而第二種則將 command 的輸出當做輸入。兩種形式一次都只讀入一行,若再執行一次,則再讀入一行。讀入的資料指定為 $0,然後分解為欄位,設定 NFNR FNR。若指定 var,則結果會指定給 var,而原來的 $0 保持不變。所以若將結果指定給變數,則目前行內容不變。若讀入成功則傳回 0,若讀到 end-of-line 則傳回 1,而因其它原因失敗時傳回 -1{N}


--------------------------------------
gsub(r,s,t)

t 字串中每個符合 r 這個常規表示式的部份,以 s 來取代。傳回值為取代之次數。若不指定 t,預設為 $0{N}


--------------------------------------
if (condition)
command
[else]
[command]

condition 條件成立,則執行 command 指令。若不成立,則執行下面的 else 後的指令。condition 可以是關係條件式或是 pattern(如 "if ($1 ~ /{Aa].*/)" )。若一次要執行多個指令則需加上 {}


--------------------------------------
index(str,substr)

傳回 substr str 內所在的位置。


--------------------------------------
int(arg)

傳回 arg 的整數值。


--------------------------------------
length(arg)

傳回 arg 的長度。若不指定 arg,預設為 $0。如此一來,length 就可以當做目前行的長度的變數使用。


--------------------------------------
log(arg)

exp 的反函數,log 傳回的是 arg 的對數值。


--------------------------------------
match(s,r)

在字串 s 中尋找符合 r 這個 常規表示式 的字串。若找到,則傳回符合字串的開頭位置,若沒找到則傳回 0。見 RSTART RLENGTH{N}


--------------------------------------
next

讀入下一行然後重新執行 pattern或程序的敘述。


--------------------------------------
print [args] [destination]

args 印出。通常 args 是欄位,但也可以是變數。若要印出字串,則需加上引用符號。欄位的印出順序和其原來的排列順序相同。若在參數中使用 "," 當分隔字元,則輸出時欄位會以 OFS 來當做分隔字元。若用空白當分隔字元,則輸出時會將這些欄位合併。destination 可以是檔案或是 pipe (如 >file)。


--------------------------------------
printf [format[, expression(s)]]

格式化輸出。輸出格式由 format 參數決定。輸出的參數個數必須符合 format 所需的個數。

format 的使用法和 C 語言中的 printf 一樣。下列為常見的格式:

%s              字串。
%d              十進位數字。
%n.mf              浮點數,n 為總共的位數,m 為小數點後的位數。
%[-]nc              c 這種格式指定最小欄位寬度。加上 - 則向左對齊,不加則向右對齊。

format 也可以含有 escape 字元。常用的有 \n(換行字元) 和 \ttab

若加上引用符號,則可以在 args 中加入字串或是空白字元。若要印出多個變數或是欄位,則必須用多個格式 format

範例:

使用下列 script

{printf ("The sum on line %s is %d \n", NR, $1+$2)}

下面是輸入:

5  5

輸出如下,加上換行

The sum on line 1 is 10.


--------------------------------------

rand()

產生介於 0 1 的亂數。這個函式在同一個 script 中執行時會傳回同一個值,若要改變其值,則需用 srand()來改變其 seed 的值。{N}


--------------------------------------
return [expr]

在函式結束前將 expr 做為傳回值傳回去。{N}


--------------------------------------
sin(x)

傳回 x sine 值,單位為弧度。


--------------------------------------
split(string,array[,sep])

string 字串分解成 array[1], ..., array[n]。在字串中每遇到一次 sep 分隔符號就分解一次。若不指定 sep,則使用預設的 FS。最後傳回所建立的陣列大小。


--------------------------------------
sprintf [format[,expression(s)]]

expression format 格式化後當做傳回值傳回。資料格式化後並不印出。{N}


--------------------------------------
sqrt(arg)

傳回 arg 開根號之值。


--------------------------------------
srand(expr)

expr 來產生一個新的亂數 seed。預設為目前時間。{N}


--------------------------------------
sub(r,s,t)

t 字串中第一個符合 r 這個常規表示式的部份,以 s 來取代。若成功則傳回 0,反之則傳回 1。若不指定 t,預設為 $0{N}


--------------------------------------
substr(string,m,[n])

string 字串中從 m 開始的 n 個字元當作字串傳回。若無 n,則從第 m 個字元到字串尾。


--------------------------------------
system(command)

執行指定的 command,然後傳回其狀態。通常狀態為 1(成功)、0(結束)或是 -1(失敗) 這個指令的輸出無法從 script 中取得。若須要指令的輸出,請見 getline{N}


--------------------------------------
tolower(str)

str 中所有大寫的字元都改為小寫後傳回字串 {G}


--------------------------------------
toupper(str)

str 中所有小寫的字元都改為大寫後傳回字串 {G}


--------------------------------------
while (condition)
command

condition 成立時執行 command(有關 condition 組成請見 if)。若要一次執行多個指令需加上 {}

沒有留言:

張貼留言

推到 Twitter!
推到 Plurk!
推到 Facebook!