awk 學習筆記


本文參考的是 ubuntu 下 gawk version 3.1.6 以及 《sed&awk》
一 . awk 簡介

awk 是一種解釋型(tawk除外)文本處理語言

二 . awk 如何運作

命令行參數
shell 會預處理命令行,獲得命令行參數(其中包括命令名),之後啓動命令並向它傳遞剩餘的參數。
系統變量ARGV:
一個關聯數組,存放命令行參數,數組下標從0到ARGC-1,ARGV[0]的值爲awk
系統變量ARGC:
命令行參數的個數
ARGV 的元素不包含AWK的選項和腳本

筆者根據 awk 的 info 手冊以及實際操作,臆測出 awk 的大致運作過程如下:
1 . 執行 -v 選項指定的賦值語句
2 . 編譯awk腳本爲某種內部形式(internal form)
3 . 執行 BEGIN 塊
4 . #如果沒有提供輸入文件
    if(ARGC == 1)
    {
    #讀取標準輸入直到輸入結束
    while(未讀到到文件末尾)#文件指標準輸入
    {
        讀取下一個記錄
        執行awk腳本
    }
    }
    #遍歷存放命令行參數的數組ARGV
    for(i = 1; i < ARGC; i++) #ARGV[0]是awk,不作爲輸入文件
    {
    if(ARGV[i] 是var=val形式)
    {
        定義全局變量var的值爲val
    }
    else  #作爲文件名處理
    {
        if(ARGV[i] 是有效的文件名)
        {
            while(未讀到文件 ARGV[i] 的末尾)
            {   
                讀取下一個記錄
                執行 awk 腳本
            }
        }
        else
        {
            輸出錯誤,指出文件名ARGV[i]無效
        }
    }
    }
5 . 執行 END 塊

從以上的流程可以看出:
1 . BEGIN 塊中  可以獲得步驟 1 中賦值語句的變量值
2 . BEGIN 塊中不可以獲得步驟 4 中賦值語句的變量值

讀者可以觀察以下腳本的運行結果:
$ touch file1 file2 'c=30' #創建三個文件
$ cat file1
1111
2222
$ cat file2
3333
4444
$ cat file3
5555
6666
$ cat 'c=30'  #文件名是賦值語句的形式
c=30
c=30
$ cat test1.awk
BEGIN{
    print "---------------------"
    print "當前在 BEGIN 塊中"
    print "a=" a
    print "b=" b
    print "c=" c
    print "共有" ,  ARGC , "個命令行參數:"
    for(i = 0; i < ARGC; i++)
        print i , ARGV[i];
}
{
    if(FNR == 1)
    {
        print "---------------------"
        print "當前正處理文件" , FILENAME
        print "a=" a
        print "b=" b
        print "c=" c
    }
    print  "第" , FNR , "行", $0
}
END{
    print "---------------------"
    print "當前在 END 塊中"
}
$ awk -v a=10 -f test1.awk file1 b=20 file2 c=30 file3
---------------------
當前在 BEGIN 塊中      #注意到BEGIN只執行一次,而且是在輸入之前
a=10                   #BEGIN塊裏只認識通過 -v 選項賦值的變量a
b=                     # 不認識
c=                     # 不認識
共有 6 個命令行參數:   #注意到,參數裏面沒有選項(-f)
0 awk                  #也沒有作爲腳本的文件名test1.awk
1 file1
2 b=20
3 file2
4 c=30
5 file3
---------------------
當前正處理文件 file1
a=10                   #-v 選項賦值的變量,所有文件都認識
b=                     # 讀入file1之後b=20才執行,file1不認識b
c=                     # c 是誰file1也不知道
第 1 行 1111
第 2 行 2222
---------------------
當前正處理文件 file2
a=10                   #-v 選項賦值的變量,所有文件都認識
b=20                   #b=20發生之後纔讀入file2,所以認識b
c=                     #肯定不認識
第 1 行 3333
第 2 行 4444
---------------------
當前正處理文件 file3
a=10
b=20
c=30                   #原來,儘管當前目錄下有名叫'c=30'的文件,但awk仍然把它當成賦值語句了
第 1 行 5555
第 2 行 6666
---------------------
當前在 END 塊中        #注意到END發生在所有輸入完畢之後
$

三 . 字符串常量
字符串常量是包括在兩個雙引號之間的一系列字符。
awk 能夠像 C 語言一樣識別字符串常量中如下轉義字符:
//        字面反斜槓
/a        響鈴(alert)
/b        退格鍵(backspace)
        作用:刪除光標左邊的字符並使光標左移一格
/f        進紙鍵(form-feed)
        作用:不清楚
/n        新行符(newline character)
/r        回車符(carriage return)
/t        水平製表符(horizontal tab)
/v        垂直製表符(vertical tab)
/xhexdigits     轉義/x之後的 16 進制字符串爲對應的字符
        /x1B 代表 ESC 字符
/ddd        將 一位,兩位,三位的十進制數轉化爲對應的字符
        /033 或 /33 代表 ESC 字符
/c        字面的 字符 c

注意:
以上轉義序列能夠被 awk 的正則表達式識別!!


四 . 正則表達式


gawk 默認支持 POSIX ERE , GAWK 獨有的轉義序列, 以及 gawk 字符串常量支持的 C 類的轉義序列。

POSIX ERE 支持以下形式的正則表達式:
c        匹配單個非元字符c
/c        匹配字面的元字符c
^        匹配字符串開始
$        匹配字符串結束
.        匹配任意字符,含換行符
[]        匹配方括號中出現的任意字符
[^]        匹配其中沒有出現的字符
REGEXP1|REGEXP2    匹配REGEXP1 或者 REGEXP2
REGEXP1REGEXP2    匹配REGEXP1 緊接着匹配 REGEXP2
REGEXP+        匹配REGEXP 的一次及以上出現
REGEXP?        匹配REGEXP 的 0 次或 1 次出現
REGEXP*        匹配REGEXP 的 0 次及以上出現
(REGEXP)    匹配REGEXP , 分組
REGEXP{n}    匹配REGEXP的 n 次出現
REGEXP{n,m}    匹配REGEXP的 n 到 m 次出現
REGEXP{n,}       匹配REGEXP的 最少 n 次出現
REGEXP{,m}    匹配REGEXP的 最多 m 次出現
字符類        [:alnum:]等
等價類        [=e=]等
collating class [.ch.] 等

GAWK 獨有的轉義序列
/y        匹配單詞開頭或者結尾的空串
/B        匹配單詞內部的空串
/`        匹配緩衝區開頭的空串
/'        匹配緩衝區結尾的空串
/w        匹配字母數字下劃線(word-constituent character)
/W        匹配非字母數字下劃線(no word-constituent character)
/<        匹配單詞開頭的空串
/>        匹配單詞結尾的空串

awk 支持的 C 類轉義序列也被 gawk 正則表達式支持:
/n
/r
/t
/v
/a
/b
/xhexdigits
/ddd

五 . 選項

-F fs
指定fs 爲字段分隔符(field separator)

-f script
將script的內容添加到腳本中去。
-f可以出現多次,awk會按順序把所有的腳本文件拼接作爲一個完整的腳本

-v var=val
設置變量var 的值爲 val,改變量賦值發生在BEGIN塊之前
如果在賦值語句var=val中出現空格,可以使用引號將該語句包圍,以此保護空格

以下選項關乎awk對正則式的理解:

--posix
支持POSIX ERE(包括範圍表達式)
支持 awk 字符串常量支持的轉義字符
不支持上述 GAWK 獨有的轉義序列

--traditional
只支持傳統的UNIX awk 正則表達式,以下均不支持:
1) 範圍表達式
2) 字符類等
3) gawk 獨有的轉義序列(更加不支持了!)
4)  awk 字符串常量所支持的那些 C 類轉義序列

--re-interval
強制支持範圍表達式,即使已經指定了 --traditional 選項

如果上訴三種選項均未指定,則 awk 對正則式作如下理解:
支持 POSIX ERE (除了範圍表達式)
支持 GAWK 支持的特殊轉義序列(/y /w等)
支持  AWK 字符串常量支持的特殊轉義字符(/ddd等)


五 . 記錄和字段
1 . 記錄(record)
1) 記錄默認由新行符分隔,新行符是內置系統變量記錄分隔符RS(record separator)的值。
2) RS 通常是一個字符,這個字符用於分隔記錄。
3) RS 如果是多個字符,則被作爲正則表達式,輸入文本中匹配該正則式的部分用於隔開記錄。但是在兼容模式下,只取第一個字符被作爲分隔符。
4) <<sed & awk>> :RS 是 awk 僅僅注意其第一個字符的唯一一個變量。
3) RS 設置爲空串(""),則記錄被空行分隔,此時,無論FS(域分隔符)被設置成什麼值,字段是由新行符隔開的。
4) FNR 記錄當前記錄在當前輸入文件中的編號,即當前記錄是當前文件的第 FNR 個記錄。
5) NR 記錄已經讀入的記錄的個數

2 . 字段(field)
1) 字段分隔符FS(field separator)用於把記錄分隔成多個字段
2) FS通常是單個字符,則字段由該字符分隔。
3) FS是空格時比較特殊,記錄中的字段之間由任意數量空格,任意數量製表符的任意排列分隔。
4) FS含多個字符時被作爲正則表達式
5) NF 記錄當前記錄中的字段數
6) FIELDWIDTH 變量一旦被設置,則 FS 的值會被忽略,即在字段分隔不起作用。
7) awk讀入記錄的同時把字段的值賦給了內置變量,有以下方式可引用字段:
----使用常量引用例如 $10
----使用變量引用例如 $i  , $NF
----使用算式返回值例如 $(2+1)
----使用函數返回值引用例如 $int(1+1)

其中,美元符叫做字段引用操作符
8) 引用負數位置的字段將導致錯誤
9) 引用 $NF 之後的字段將導致 awk 自動生成該字段及之前本沒有的字段並各賦值爲空串,NF被修改,$0 被調整。

六 . 關聯數組

awk 中所有的數組都是關聯數組,表達了一種從字符串到字符串的映射關係。

1 . 關聯數組特點
1) 物理組織無序
2) 模擬多維數組
3) 原理是字符串映射

2 . 下標
關聯數組的下標是括在一對方括號之間的表達式列表,如果有多個表達式,則表達式間用英文逗號分隔。
1)  一維數組
數組是從一個字符串到另一個字符串的映射,key_str --> val_str ,前者是鍵。
-- arr[ key_str ] 形式,awk 訪問以變量   key_str 的值爲鍵的數組元素
   有個例外,當 key_str 是一個數字時,awk 會把它轉換爲字符串,此時arr[key_str]等價於arr["key_str"]
-- arr["key_str"] 形式,awk 訪問以字符串 key_str     爲鍵的數組元素
-- 訪問某個不存在的數組元素時,awk會創建該數組元素,數組元素初始化爲空串

例子:
$ awk 'BEGIN{a[1] = "1111";  print "a[/"1/"]=" , a["1"];  print "a[ 1 ]=" , a[1] }' file
a["1"]= 1111
a[ 1 ]= 1111
$ awk 'BEGIN{a["1"] = "111"; print length(a); print a[var] ; print length(a)}' file
1                 # print length(a)輸出 a 的長度,當時有一個元素 a["1"]
                  # a[var] 相當於 print a[""],而a[""]元素不存在,輸出空串
2                 # awk 自動創建了數組元素 a[""]並初始化爲空串 , 所以數組大小變爲 2
$


2)  多維數組
多維數組通過在方括號之間用逗號隔開各維的鍵進行訪問,所有的鍵值都被作爲字符串。
數字鍵會被轉換爲字符串,其中,實數轉換爲字符串可能會丟失信息,實數轉換受 CONFMT 的影響。
多維數組與一維數組遵循同樣的映射原理:
通過把方括號中各字符串用系統變量 SUBSEP 的值銜接起來得到 key_str ,然後映射到 val_str 。

例子:
i = "30"
j = 20
a["mm",i,j] = "zhong"      相當於   a["30" , "30" , 20] = "zhong"
                           相當於   a["mm" , "30" , "20"] = "zhong"     

意爲把數組元素 a["mm/03430nn"] 賦值爲串 "zhong",其中/034 是SUBSEP 的默認值。

3 . 刪除
通過 delete arr["index"] 刪除單個元素;delete arr 刪除整個數組。

4 . 遍歷
---方法1
while(key in arr) #遍歷 arr 的所有鍵值,如果是多維數組,用(key1,key2,key3)放在 key 的位置。

---方法2
如果能夠在構建數組的時候,用連續的或者大小有規律的鍵值,則可以用for循環遍歷例如:
for(i = 1; i <= NF; i++)
    arr[i] = $i;
for(i = 1; i <= NF; i++)
    print arr[i];

六 . 操作符(按優先級逐漸降低)
()        分組操作符
$        字段引用操作符
++ --        遞增遞減
^        指數
+ - !        一元加,一元減,邏輯取反
* / %        乘除取模
+ -        二元加,二元減
space        字符串連接符,很牛逼!
| |&        管道I/O,用於print , printf,getline
< >        關係運算符
<= >=
!= ==        
~ !~        匹配,不匹配,字符串匹配的,超牛逼!
in        判斷關聯數組中是否存在以某個鍵爲下標的元素
&&        邏輯與
||        邏輯或
?:        C格式的條件語句,expr?expr1:expr2,如果expr爲真,則該條件語句值爲expr1的值;否則expr2。
= += -=        賦值,^=是將指數運算的結果賦給左參數
*= /= %= ^=   

八 . 語句格式
awk 程序的框架是由一個或者多個如下的語句組組成:
condition{ statements }

其中可能出現兩個特殊語句組
BEGIN{ statements }  和  END{ statements }

1 . BEGIN 語句組(如果有),作爲第一個語句組,-v選項賦值語句之後,第一個記錄讀入之前執行。
2 . END 語句組(如果有),作爲最後一個語句組。在所有輸入結束之後執行。
3 . 每次讀入一個記錄,剩下的語句組都要判斷條件是否滿足,如果滿足就執行。
4 . condition{statements}的condition如果缺失,則對所有記錄都執行方括號中的語句。
5 . statements 如果缺失,則默認執行 print 函數,輸出 $0
6 . 左花括號({) 必須和condition在同一行,condition 和 { 之間可以隔着空白符。
7 . statements中的每個statement 可以用分號隔開

condition 語句可以是以下形式:

BEGIN
-v選項賦值語句之後,第一個記錄讀入之前執行方括號中的語句。

END
在所有輸入結束之後執行方括號中的語句。

/REGEXP/
當前記錄能夠匹配正則表達式REGEXP時,才執行方括號中的語句。
正則式的匹配能力須參考上面的部分。

表達式
《sed&awk》:表達式通過計算返回一個值,表達式由數字,字符串常量,變量,操作符,函數和正則表達式組成。
利用表達式的值作爲判斷依據,如果爲0或者空則不執行

condition && condition 和  condition || condition
表示兩個條件的邏輯與 和 邏輯或

condition ? condition1 : condition2
當condition滿足時,如果condition1滿足則執行方括號中的語句;
否則,當condition2滿足時則執行方括號中的語句。

(condition)
就是把條件用括號包圍起來而已

! condition
當condition不滿足時,才執行方括號中的語句。

condition1 , condition2
從第一個滿足condition1的記錄開始(包含),到該記錄之後第一個滿足condition2的記錄結束(含該記錄)
都執行方括號中的語句。

例子:
# 不是BEGIN的條件下
! BEGIN{ statements }

# 注意左花括號之前可以有很多空白符
# 注意使用圓括號將表達式括起來不是必須的
0{ statements_impossible_to_execute }
1 - 1{ statements_impossible_to_execute }
(1+1)    { statements_doomed_to_excute }

# 注意匹配的是擴展的正則表達式(ERE)
/^/t+/{ statements }

# 注意使用ERE的範圍表達式時需要有 --posix 或者 --re-interval 選項
awk --posix '/a{2,4}/{print}' data


八 . 系統變量

FS        字段分隔符
RS        記錄分隔符
OFS        輸出字段分隔符,默認爲空格;影響print的輸出。
        print $0 輸出當前記錄,字段之間由OFS的值隔開;
        print "a" , "b" a和 b 之間由 OFS值隔開。
ORS        輸出記錄分隔符,默認爲新行符;影響print的輸出。
        每個 print 語句最後都會輸出 ORS    的值
ARGV        關聯數組,用於存儲傳遞給 awk 的輸入文件名
        有 ARGC    個元素,下標因此從0 到 AGRC-1
        ARGV[0] 等於 "awk"
        ARGV中的文件名如果是等式形式,則被awk作爲賦值語句。
ARGC        數組ARGV中元素的個數,ARGC>= 1; 因爲 ARGV[0] 是 "awk"
FNR        當前記錄在當前輸入文件中的位置,即當前文件的第FNR個記錄
FILENAME    當前輸入文件
RSTART        參考match 函數
RLENGTH        參考match 函數
SUBSEP        在多維數組的字符串映射中,用於把各維的鍵值銜接起來形成整體的鍵值
        默認值是 "/034"
CONVFMT        數字轉換的格式,默認值"%.6g"
ENVIRON        以環境變量名(大寫)爲鍵值的關聯數組,可以通過環境變量名訪問數組元素。
OFMT        數字的輸出格式,默認是"%.6g"

還有一些系統變量,不熟悉,不寫了:
ERRNO    IGNORECASE LINT    PROCINFO TEXTDOMAIN RT


九 . statements
statements 支持 C-style 條件和循環語句,break,continue ;以及其它語句。
------------------------------------------------------------------------------------
if(條件){語句組}[else {語句組}]
while(條件){語句組}
do{語句組}while(條件)
for(語句1;語句2;語句3){語句組}
for(var_key in arr){語句組}
break
continue
delete arr[i]
delete arr
exit [exitcode]

十 . 函數

1 . 算術函數
int ()
返回強制轉換後得到的整數
cos(expr)
返回餘弦值
sin(expr)
返回正弦值
atan2(y,x)
返回以弧度計算的(y/x)的反正切值
loh(expr)
返回自然對數值
exp(expr)
返回對數值
sqrt(expr)
返回開方後的值
rand()
返回隨機產生的小於1大於等於0的值
srand([expr])
設置rand()函數的種子值爲 expr 的返回值,如果沒有expr 則以當天時間爲種子。
<<sed&awk>>:如果沒有調用srand(),awk在開始執行程序之前默認以某個常量爲參數調用srand(),使得你的程序在每次運行時都從同一個種子數開始。

2 . 字符串函數
length()
返回字符串或者數組的長度

index(str,target)
返回字符串 target 在字符串 str 中第一次出現的位置,如果沒有,返回 0;字符串下標從 1 開始。

match(str , /regexp/ , [, arr])
在字符串 str 中尋找匹配 regexp 的子串,返回第一個匹配子串的位置,如果失配,返回0。
設置系統變量 RSTART 爲匹配子串的起始位置,RLENGTH爲匹配子串的長度;失配則RSTART爲 0 ,RLENGTH 爲 -1。
如果 arr 這個數組,則 arr 被清空,並從下標 "1" 開始保存找到的匹配regexp的子串。
所有匹配的子串被保存在 arr["0"] 中。

split(str , arr [, /separator_regexp/])
把字符串 str 分解到數組 arr 中去,使用匹配正則式 separator_regexp 的子串作爲分隔符。
如果沒有提供 serarator_regexp 則使用 FS 的值作爲分隔符。
返回分解得到的串的個數,即數組的大小(如果有)

sub(/regexp/ , replacement [,str])
把 str 中第一個匹配正則式 regexp 的子串替換成 replacement 字符串。返回替換的個數。
如果沒有提供 str ,使用 $0 。
replacement 中出現的 & 具有特殊含義,被替換成匹配 regexp 的那部分子串。
要轉義 replacement 中的 & 使用 //&
此外,& 必須被包含在雙引號之間才能被識別,否則出錯。

gsub(/regexp/ , replacement [,str])
把 str 中所有匹配正則式 regexp 的子串替換成 replacement 字符串。返回替換的個數。
其餘說明與 sub 同。

tolower(str)
返回字符串 str 中所有大寫字母全部被轉換爲小寫字母之後的串。原串不改變。

toupper(str)
返回字符串 str 中所有小寫字母全部被轉換爲大寫字母之後的串。原串不改變。

substr(str , pos [,len])
返回 str 第 pos 個字符開始的長度爲 len (len >=1) 的串
如果 len 未提供,則返回直到 str 末尾的串
如果 len <= 0 則返回空串


3 . 自定義函數

格式
function func_name(parameter_list){
    statements;
    return [rt_val]
}

1) 定義函數時,func_name 和左圓括號之間可以有空格,但是調用函數時不允許。系統自帶函數例外。
2) 自定義函數中定義的變量具有全局性質,將它們定義在圓括號內的形式參數之後,可使成爲局部變量。
3) 調用自定義函數時,實際參數不必包括函數內的局部變量。
4) 應該具有返回值,如果不顯式返回,則默認返回空串。
5) <<sed&awk>>:自定義函數的定義可以放在腳本中模式操作規則可以出現的任何地方,通常可以放在腳本中模式操作規則之前。

4 . print

1) print
輸出 $0 , 後跟 ORS

2) print expr_list
---每個表達式(expr)之間用逗號和空格的組合進行分隔。
---每個表達式的結果會被作爲字符串輸出,表達式之間輸出OFS的值
---print 語句的最後輸出 ORS 的值
---單個表達式內的串之間的空格符是作爲字符串銜接符(print "x" "y" 相當於 print "xy")
---可以重定向到文件
---<<sed&awk>>: 規定 > 出現在任何打印語句的參數列表中時被看作是重定向操作符,如果想要 > 在參數列表中被看作關係運算符,可以使用圓括號將表達式或者參數列表括起來。

5 . printf("format_expression" [, arguments])
借用C程序設計語言printf進行格式化輸出,括號可以省略。
format_expression 由雙引號括起來,其中%之後的字符作爲格式轉換說明符; arguments 由逗號分隔,第 n 個 argument 對應於 format_expression 第 n 個 %轉義說明符; 意爲把該 argument 對應的串轉換爲該格式轉換說明符指明的格式並輸出。

以下爲 % 與格式轉換說明符的組合:
%c        作爲ASCII字符輸出
%d        作爲整數輸出
%i        作爲整數輸出
%e        以浮點格式輸出
%E        以浮點格式輸出
%f        以浮點格式輸出
%g        e或f的轉換格式,長度最短,末尾的 0 被去掉
%G        E或f的轉換格式,長度最短,末尾的 0 被去掉
%O        作爲無符號八進制數輸出
%s        作爲字符串輸出
%u        作爲無符號的十進制數輸出
%x        作爲無符號的十六進制數輸出,a-f表示 10-15
%X        作爲無符號的十六進制數輸出,A-F表示 10-15
%%        字面的%

上述每一個格式轉換說明符(除了%%之外)都可以擴充爲以下形式:
        %-width.precision format_specifier
width 指定域寬度,指定域寬的輸出會自動向右對齊,如果想想左對齊,可以在百分號之後添加減號(-),見上式。
pricision 指定小數點之後的數字位數
數字的默認轉換格式由系統變量 CONFMT (有的是OFMT) 指定,默認爲 "%.6g"

也可以是以下形式:
        % width.precision format_specifier
        %0width.precision format_specifier
        %+width.precision format_specifier
        %#width.precision format_specifier

關於 printf 函數,不熟悉,只把參考文件貼出來:
-      The expression should be left-justified within its field.

space  For  numeric  conversions,  prefix positive values with a space,
       and negative values with a minus sign.

+      The plus sign, used before the width modifier (see below),  says
       to  always  supply  a  sign for numeric conversions, even if the
       data to be formatted is positive.  The  +  overrides  the  space
       modifier.

#      Use  an  “alternate  form” for certain control letters.  For %o,
       supply a leading zero.  For %x, and %X, supply a leading  0x  or
       0X  for  a  nonzero  result.   For %e, %E, %f and %F, the result
       always contains a decimal point.  For %g, and %G, trailing zeros
       are not removed from the result.

0      A  leading 0 (zero) acts as a flag, that indicates output should
       be padded with zeroes instead of spaces.  This applies  even  to
       non-numeric  output  formats.  This flag only has an effect when
       the field width is wider than the value to be printed.

width  The field should be padded to this width.  The field is normally
       padded  with  spaces.  If the 0 flag has been used, it is padded
       with zeroes.

.prec  A number that specifies the precision to use when printing.  For
       the  %e,  %E,  %f  and %F, formats, this specifies the number of
       digits you want printed to the right of the decimal point.   For
       the  %g, and %G formats, it specifies the maximum number of sig‐
       nificant digits.  For the %d, %o, %i, %u, %x, and %X formats, it
       specifies  the  minimum  number  of digits to print.  For %s, it
       specifies the maximum number of characters from the string  that
       should be printed.


6 . getline

1) getline
讀取下一個記錄,覆蓋$0,設置FNR NR NF

2) getline "-"
從標準輸入讀取一行

3) getline <"filename"
讀入文件filename的下一個記錄,只更新NF

4) getline var
讀取下一個記錄,存入變量var ,設置 FNR NR。 $0 不變,NF 不變

5) getline var <"file_name"
讀入文件file的下一個記錄,存入變量var 。 FNR NR NF $0均不變。

注:
1) 不能寫成 getline() , 它的語法不允許有圓括號。
2) 返回值不是字符串
3) 成功讀取返回 1 ;讀到文件末尾返回 0 ;遇到錯誤返回 -1
4) 從流中/文件/管道中讀取時,可以直接以字符串常量指定文件名,也可以通過變量提供。

7 . close

用於關閉已經打開的文件或管道,以此可以
1)限制打開的文件和管道的數量
2)關閉一個管道可以運行同一個命令兩次
3)關閉一個管道使得其輸出的成果可以被訪問

例子2):
$ cat test.awk
{
    "date" | getline var
    print var
    close("date")            #關閉管道
    "date" | getline var2
    print var2
}
$ awk -f test.awk file
Fri Mar  4 21:35:09 CST 2011
Fri Mar  4 21:35:09 CST 2011
$ cat test.awk
{
    "date" | getline var
    print var
#    close("date")            #不關閉管道
    "date" | getline var2
    print var2
}
$ awk -f test.awk file            #產生空行
Fri Mar  4 21:35:09 CST 2011

$


例子3):
$ cat test.awk
{
    print $0 | "sort > outcome"
}
END{
    close("sort > outcome")  #關閉管道
    while(getline var<"outcome"){
        print var
    }
}
$ cat data
aa
bb
ff
cc
$ awk -f test.awk data
$ cat outcome
aa
bb
cc
ff
$


8 . next

讀入下一個記錄,修改$0,NF ,NR , FNR
如果已經讀到文件末尾,那麼執行END塊(如果有)
否則從第一個 condition{statements}重新開始執行
例子:
$ cat test.awk
{
    print "next 前"
    print "$0 =" $0
    print "FNR=" FNR
    print "NF =" NF
    print "NR =" NR
    next
    print "next 後"
    print "$0 =" $0
    print "FNR=" FNR
    print "NF =" NF
    print "NR =" NR
}
END{
    print "在 END 中"
}
$ cat data
aa bb
aa bb cc dd
$ awk -f test.awk data
next 前
$0 =aa bb            #file的第一行
FNR=1
NF =2
NR =1
next 前                #注意,不是 "next 後"
$0 =aa bb cc dd            #file的第二行
FNR=2
NF =4
NR =2
在 END 中
$


9 . nextfile
讀入下一個文件的第一個記錄,修改$0 , NF , NR , FNR
如果發現所有文件的輸入數據都已經讀完,執行END塊(如果有)
否則從第一個 condition{statements}重新開始執行

10 . exit
exit 使得主輸入循環退出並將控制轉移到 END 規則,如果END存在的話。

11 . system("command_line")
執行 command_line , 返回命令的退出狀態(exit status)

補充內容:
1 . 關於註釋
與 sed 不同,awk 允許在程序的任何地方添加註釋

2 . 關於斷行的技巧
一種處理斷行的方法就是使用 length 獲得每個字段的長度,這樣,當累計的長度超過某個特定的數據時,就可以指定一個換行。

3 . 看不懂的
注意, awk 和sed 不一樣,不能“記住”前面的正則式,即不能用語法// 來引用最後的正則表達式。

第八章,有兩個語句能影響輸入循環,next 和 exit 。一些 awk 不允許在用戶自定義的函數中使用 next 語句。exit 使得主輸入循環退出並將控制轉移到 END 規則,如果 END 存在的話。如果沒有定義END 規則或者在end 中使用exit 則終止腳本的執行。

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