1. awk簡介 2. awk命令格式和選項 2.1. awk的語法有兩種形式 2.2. 命令選項 3. 模式和操作 3.1. 模式 3.2. 操作 4. awk的環(huán)境變量 5. awk運算符 6. 記錄和域 6.1. 記錄 6.2. 域 6.3. 域分隔符 7. gawk專用正則表達式元字符 8. POSIX字符集 9. 匹配操作符(~) 10. 比較表達式 11. 范圍模板 12. 一個驗證passwd文件有效性的例子 13. 幾個實例 14. awk編程 14.1. 變量 14.2. BEGIN模塊 14.3. END模塊 14.4. 重定向和管道 14.5. 條件語句 14.6. 循環(huán) 14.7. 數(shù)組 14.8. awk的內建函數(shù) 15. How-to
正文
1. awk簡介 awk 是一種編程語言,用于在linux/unix下對文本和數(shù)據(jù)進行處理。數(shù)據(jù)可以來自標準輸入、一個或多個文件,或其它命令的輸出。它支持用戶自定義函數(shù)和動態(tài)正則表達式等先進功能,是linux/unix下的一個強大編程工具。它在命令行中使用,但更多是作為腳本來使用。awk的處理文本和數(shù)據(jù)的方式是這樣的,它逐行掃描文件,從第一行到最后一行,尋找匹配的特定模式的行,并在這些行上進行你想要的操作。如果沒有指定處理動作,則把匹配的行顯示到標準輸出 (屏幕),如果沒有指定模式,則所有被操作所指定的行都被處理。awk分別代表其作者姓氏的第一個字母。因為它的作者是三個人,分別是Alfred Aho、Brian Kernighan、Peter Weinberger。gawk是awk的GNU版本,它提供了Bell實驗室和GNU的一些擴展。下面介紹的awk是以GUN的gawk為例的,在 linux系統(tǒng)中已把awk鏈接到gawk,所以下面全部以awk進行介紹。
2. awk命令格式和選項 2.1. awk的語法有兩種形式
awk [options] 'script' var=value file(s) |
awk [options] -f scriptfile var=value file(s) |
2.2. 命令選項
-F fs or --field-separator fs 指定輸入文件折分隔符,fs是一個字符串或者是一個正則表達式,如-F:。
-v var=value or --asign var=value 賦值一個用戶定義變量。
-f scripfile or --file scriptfile 從腳本文件中讀取awk命令。
-mf nnn and -mr nnn 對nnn值設置內在限制,-mf選項限制分配給nnn的最大塊數(shù)目;-mr選項限制記錄的最大數(shù)目。這兩個功能是Bell實驗室版awk的擴展功能,在標準awk中不適用。
-W compact or --compat, -W traditional or --traditional 在兼容模式下運行awk。所以gawk的行為和標準的awk完全一樣,所有的awk擴展都被忽略。
-W copyleft or --copyleft, -W copyright or --copyright 打印簡短的版權信息。
-W help or --help, -W usage or --usage 打印全部awk選項和每個選項的簡短說明。
-W lint or --lint 打印不能向傳統(tǒng)unix平臺移植的結構的警告。
-W lint-old or --lint-old 打印關于不能向傳統(tǒng)unix平臺移植的結構的警告。
-W posix 打開兼容模式。但有以下限制,不識別:\x、函數(shù)關鍵字、func、換碼序列以及當fs是一個空格時,將新行作為一個域分隔符;操作符**和**=不能代替^和^=;fflush無效。
-W re-interval or --re-inerval 允許間隔正則表達式的使用,參考(grep中的Posix字符類),如括號表達式[[:alpha:]]。
-W source program-text or --source program-text 使用program-text作為源代碼,可與-f命令混用。
-W version or --version 打印bug報告信息的版本。
|
3. 模式和操作 awk腳本是由模式和操作組成的:
pattern {action} 如$ awk '/root/' test,或$ awk '$3 < 100' test |
兩者是可選的,如果沒有模式,則action應用到全部記錄,如果沒有action,則輸出匹配全部記錄。默認情況下,每一個輸入行都是一條記錄,但用戶可通過RS變量指定不同的分隔符進行分隔。
3.1. 模式 模式可以是以下任意一個: /正則表達式/:使用通配符的擴展集。 關系表達式:可以用下面運算符表中的關系運算符進行操作,可以是字符串或數(shù)字的比較,如$2>%1選擇第二個字段比第一個字段長的行。 模式匹配表達式:用運算符~(匹配)和~!(不匹配)。 模式,模式:指定一個行的范圍。該語法不能包括BEGIN和END模式。 BEGIN:讓用戶指定在第一條輸入記錄被處理之前所發(fā)生的動作,通常可在這里設置全局變量。 END:讓用戶在最后一條輸入記錄被讀取之后發(fā)生的動作。 3.2. 操作 操作由一人或多個命令、函數(shù)、表達式組成,之間由換行符或分號隔開,并位于大括號內。主要有四部份: 變量或數(shù)組賦值 輸出命令 內置函數(shù) 控制流命令 4. awk的環(huán)境變量 Table 1. awk的環(huán)境變量
變量 |
描述 |
$n |
當前記錄的第n個字段,字段間由FS分隔。 |
$0 |
完整的輸入記錄。 |
ARGC |
命令行參數(shù)的數(shù)目。 |
ARGIND |
命令行中當前文件的位置(從0開始算)。 |
ARGV |
包含命令行參數(shù)的數(shù)組。 |
CONVFMT |
數(shù)字轉換格式(默認值為%.6g) |
ENVIRON |
環(huán)境變量關聯(lián)數(shù)組。 |
ERRNO |
最后一個系統(tǒng)錯誤的描述。 |
FIELDWIDTHS |
字段寬度列表(用空格鍵分隔)。 |
FILENAME |
當前文件名。 |
FNR |
同NR,但相對于當前文件。 |
FS |
字段分隔符(默認是任何空格)。 |
IGNORECASE |
如果為真,則進行忽略大小寫的匹配。 |
NF |
當前記錄中的字段數(shù)。 |
NR |
當前記錄數(shù)。 |
OFMT |
數(shù)字的輸出格式(默認值是%.6g)。 |
OFS |
輸出字段分隔符(默認值是一個空格)。 |
ORS |
輸出記錄分隔符(默認值是一個換行符)。 |
RLENGTH |
由match函數(shù)所匹配的字符串的長度。 |
RS |
記錄分隔符(默認是一個換行符)。 |
RSTART |
由match函數(shù)所匹配的字符串的第一個位置。 |
SUBSEP |
數(shù)組下標分隔符(默認值是\034)。 |
5. awk運算符 Table 2. 運算符
運算符 |
描述 |
= += -= *= /= %= ^= **= |
賦值 |
: |
C條件表達式 |
|| |
邏輯或 |
&& |
邏輯與 |
~ ~! |
匹配正則表達式和不匹配正則表達式 |
< <= > >= != == |
關系運算符 |
空格 |
連接 |
+ - |
加,減 |
* / & |
乘,除與求余 |
+ - ! |
一元加,減和邏輯非 |
^ *** |
求冪 |
++ -- |
增加或減少,作為前綴或后綴 |
$ |
字段引用 |
in |
數(shù)組成員 |
6. 記錄和域 6.1. 記錄 awk把每一個以換行符結束的行稱為一個記錄。 記錄分隔符:默認的輸入和輸出的分隔符都是回車,保存在內建變量ORS和RS中。 $0變量:它指的是整條記錄。如$ awk '{print $0}' test將輸出test文件中的所有記錄。 變量NR:一個計數(shù)器,每處理完一條記錄,NR的值就增加1。如$ awk '{print NR,$0}' test將輸出test文件中所有記錄,并在記錄前顯示記錄號。 6.2. 域 記錄中每個單詞稱做“域”,默認情況下以空格或tab分隔。awk可跟蹤域的個數(shù),并在內建變量NF中保存該值。如$ awk '{print $1,$3}' test將打印test文件中第一和第三個以空格分開的列(域)。 6.3. 域分隔符 內建變量FS保存輸入域分隔符的值,默認是空格或tab。我們可以通過-F命令行選項修改FS的值。如$ awk -F: '{print $1,$5}' test將打印以冒號為分隔符的第一,第五列的內容。 可以同時使用多個域分隔符,這時應該把分隔符寫成放到方括號中,如$awk -F'[:\t]' '{print $1,$3}' test,表示以空格、冒號和tab作為分隔符。 輸出域的分隔符默認是一個空格,保存在OFS中。如$ awk -F: '{print $1,$5}' test,$1和$5間的逗號就是OFS的值。 7. gawk專用正則表達式元字符 一般通用的元字符集就不講了,可參考我的Sed和Grep學習筆記。以下幾個是gawk專用的,不適合unix版本的awk。 \Y 匹配一個單詞開頭或者末尾的空字符串。 \B 匹配單詞內的空字符串。 \< 匹配一個單詞的開頭的空字符串,錨定開始。 \> 匹配一個單詞的末尾的空字符串,錨定末尾。 \w 匹配一個字母數(shù)字組成的單詞。 \W 匹配一個非字母數(shù)字組成的單詞。 \‘ 匹配字符串開頭的一個空字符串。 \' 匹配字符串末尾的一個空字符串。 8. POSIX字符集 待完善 9. 匹配操作符(~) 用來在記錄或者域內匹配正則表達式。如$ awk '$1 ~/^root/' test將顯示test文件第一列中以root開頭的行。 10. 比較表達式
conditional expression1 ? expression2: expression3 |
例如:
$ awk '{max = {$1 > $3} ? $1: $3: print max}' test |
如果第一個域大于第三個域,$1就賦值給max,否則$3就賦值給max。
$ awk '$1 + $2 < 100' test |
如果第一和第二個域相加大于100,則打印這些行。
$ awk '$1 > 5 && $2 < 10' test |
如果第一個域大于5,并且第二個域小于10,則打印這些行。 11. 范圍模板 范圍模板匹配從第一個模板的第一次出現(xiàn)到第二個模板的第一次出現(xiàn)之間所有行。如果有一個模板沒出現(xiàn),則匹配到開頭或末尾。如$ awk '/root/,/mysql/' test將顯示root第一次出現(xiàn)到mysql第一次出現(xiàn)之間的所有行。 12. 一個驗證passwd文件有效性的例子
$ cat /etc/passwd | awk -F: '\ NF != 7{\ printf("line %d,does not have 7 fields:%s\n",NR,$0)}\ $1 !~ /[A-Za-z0-9]/{printf("line %d,non alpha and numeric user id:%d: %s\n,NR,$0)}\ $2 == "*" {printf("line %d, no password: %s\n",NR,$0)}' |
cat把結果輸出給awk,awk把域之間的分隔符設為冒號。 如果域的數(shù)量(NF)不等于7,就執(zhí)行下面的程序。 printf打印字符串"line ?? does not have 7 fields",并顯示該條記錄。 如果第一個域沒有包含任何字母和數(shù)字,printf打印“no alpha and numeric user id" ,并顯示記錄數(shù)和記錄。 如果第二個域是一個星號,就打印字符串“no passwd”,緊跟著顯示記錄數(shù)和記錄本身。 13. 幾個實例 打印所有以模式no或so開頭的行。
如果記錄以n或s開頭,就打印這個記錄。
$ awk '/^[ns]/{print $1}' test |
如果第一個域以兩個數(shù)字結束就打印這個記錄。
$ awk '$1 ~/[0-9][0-9]$/(print $1}' test |
如果第一個或等于100或者第二個域小于50,則打印該行。
$ awk '$1 == 100 || $2 < 50' test |
如果第一個域不等于10就打印該行。
如果記錄包含正則表達式test,則第一個域加10并打印出來。
$ awk '/test/{print $1 + 10}' test |
如果第一個域大于5則打印問號后面的表達式值,否則打印冒號后面的表達式值。
$ awk '{print ($1 > 5 ? "ok "$1: "error"$1)}' test |
打印以正則表達式root開頭的記錄到以正則表達式mysql開頭的記錄范圍內的所有記錄。如果找到一個新的正則表達式root開頭的記錄,則繼續(xù)打印直到下一個以正則表達式mysql開頭的記錄為止,或到文件末尾。
$ awk '/^root/,/^mysql/' test |
14. awk編程 14.1. 變量 在awk中,變量不需要定義就可以直接使用,變量類型可以是數(shù)字或字符串。 賦值格式:
Variable = expression,如$ awk '$1 ~/test/{count = $2 + $3; print count}' test |
上式的作用是,awk先掃描第一個域,一旦test匹配,就把第二個域的值加上第三個域的值,并把結果賦值給變量count,最后打印出來。 awk可以在命令行中給變量賦值,然后將這個變量傳輸給awk腳本。如
$ awk -F: -f awkscript month=4 year=2004 test |
上式的month和year都是自定義變量,分別被賦值為4和2004。在awk腳本中,這些變量使用起來就象是在腳本中建立的一樣。注意,如果參數(shù)前面出現(xiàn)test,那么在BEGIN語句中的變量就不能被使用。 域變量也可被賦值和修改,如
$ awk '{$2 = 100 + $1; print }' test |
上式表示,如果第二個域不存在,awk將計算表達式100加$1的值,并將其賦值給$2,如果第二個域存在,則用表達式的值覆蓋$2原來的值。再例如:
$ awk '$1 == "root"{$1 ="test";print}' test |
如果第一個域的值是“root”,則把它賦值為“test”,注意,字符串一定要用雙引號。 內建變量的使用。變量列表在前面已列出,現(xiàn)在舉個例子說明一下。
$ awk -F: '{IGNORECASE=1; $1 == "MARY"{print NR,$1,$2,$NF}'test |
把IGNORECASE設為1代表忽略大小寫,打印第一個域是mary的記錄數(shù)、第一個域、第二個域和最后一個域。
|