九. awk實用功能:
和sed一樣,awk也是逐行掃描文件的,從第一行到最后一行,尋找匹配特定模板的行,並在這些行上運行“選擇”動作。如果一個模板沒有指定動作,這些匹配的行就被顯示在屏幕上。如果一個動作沒有模板,所有被動作指定的行都被處理。
1. awk的基本格式:
/> awk 'pattern' filename
/> awk '{action}' filename
/> awk 'pattern {action}' filename
具體應用方式分別見如下三個用例:
/> cat employees
Tom Jones 4424 5/12/66 543354
Mary Adams 5346 11/4/63 28765
Sally Chang 1654 7/22/54 650000
Billy Black 1683 9/23/44 336500
/> awk '/Mary/' employees #打印所有包含模板Mary的行。
Mary Adams 5346 11/4/63 28765
#打印文件中的第一個字段,這個域在每一行的開始,缺省由空格或其它分隔符。
/> awk '{print $1}' employees
Tom
Mary
Sally
Billy
/> awk '/Sally/{print $1, $2}' employees #打印包含模板Sally的行的第一、第二個域字段。
Sally Chang
2. awk的格式輸出:
awk中同時提供了print和printf兩種打印輸出的函數,其中print函數的參數可以是變量、數值或者字符串。字符串必須用雙引號引用,參數 用逗號分隔。如果沒有逗號,參數就串聯在一起而無法區分。這里,逗號的作用與輸出文件的分隔符的作用是一樣的,只是后者是空格而已。下面給出基本的轉碼序 列:
轉碼 | 含義 |
\n | 換行 |
\r | 回車 |
\t | 制表符 |
/> date | awk '{print "Month: " $2 "\nYear: ", $6}'
Month: Oct
Year: 2011
/> awk '/Sally/{print "\t\tHave a nice day, " $1,$2 "\!"}' employees
Have a nice day, Sally Chang!
在打印數字的時候你也許想控制數字的格式,我們通常用printf來完成這個功能。awk的特殊變量OFMT也可以在使用print函數的時候,控制數字的打印格式。它的默認值是"%.6g"----小數點后面6位將被打印。
/> awk 'BEGIN { OFMT="%.2f"; print 1.2456789, 12E-2}'
1.25 0.12
現在我們介紹一下功能更為強大的printf函數,其用法和c語言中printf基本相似。下面我們給出awk中printf的格式化說明符列表:
格式化說明符 | 功能 | 示例 | 結果 |
%c | 打印單個ASCII字符。 | printf("The character is %c.\n",x) | The character is A. |
%d | 打印十進制數。 | printf("The boy is %d years old.\n",y) | The boy is 15 years old. |
%e | 打印用科學記數法表示的數。 | printf("z is %e.\n",z) | z is 2.3e+01. |
%f | 打印浮點數。 | printf("z is %f.\n",z) | z is 2.300000 |
%o | 打印八進制數。 | printf("y is %o.\n",y) | y is 17. |
%s | 打印字符串。 | printf("The name of the culprit is %s.\n",$1); | The name of the culprit is Bob Smith. |
%x | 打印十六進制數。 | printf("y is %x.\n",y) | y is f. |
注:假設列表中的變臉值為x = A, y = 15, z = 2.3, $1 = "Bob Smith"
/> echo "Linux" | awk '{printf "|%-15s|\n", $1}' # %-15s表示保留15個字符的空間,同時左對齊。
|Linux |
/> echo "Linux" | awk '{printf "|%15s|\n", $1}' # %-15s表示保留15個字符的空間,同時右對齊。
| Linux|
#%8d表示數字右對齊,保留8個字符的空間。
/> awk '{printf "The name is %-15s ID is %8d\n", $1,$3}' employees
The name is Tom ID is 4424
The name is Mary ID is 5346
The name is Sally ID is 1654
The name is Billy ID is 1683
3. awk中的記錄和域:
awk中默認的記錄分隔符是回車,保存在其內建變量ORS和RS中。$0變量是指整條記錄。
/> awk '{print $0}' employees #這等同於print的默認行為。
Tom Jones 4424 5/12/66 543354
Mary Adams 5346 11/4/63 28765
Sally Chang 1654 7/22/54 650000
Billy Black 1683 9/23/44 336500
變量NR(Number of Record),記錄每條記錄的編號。
/> awk '{print NR, $0}' employees
1 Tom Jones 4424 5/12/66 543354
2 Mary Adams 5346 11/4/63 28765
3 Sally Chang 1654 7/22/54 650000
4 Billy Black 1683 9/23/44 336500
變量NF(Number of Field),記錄當前記錄有多少域。
/> awk '{print $0,NF}' employees
Tom Jones 4424 5/12/66 543354 5
Mary Adams 5346 11/4/63 28765 5
Sally Chang 1654 7/22/54 650000 5
Billy Black 1683 9/23/44 336500 5
#根據employees生成employees2。sed的用法可以參考上一篇blog。
/> sed 's/[[:space:]]\+\([0-9]\)/:\1/g;w employees2' employees
/> cat employees
Tom Jones:4424:5/12/66:543354
Mary Adams:5346:11/4/63:28765
Sally Chang:1654:7/22/54:650000
Billy Black:1683:9/23/44:336500
/> awk -F: '/Tom Jones/{print $1,$2}' employees2 #這里-F選項后面的字符表示分隔符。
Tom Jones 4424
變量OFS(Output Field Seperator)表示輸出字段間的分隔符,缺省是空格。
/> awk -F: '{OFS = "?"}; /Tom/{print $1,$2 }' employees2 #在輸出時,域字段間的分隔符已經是?(問號)了
Tom Jones?4424
對於awk而言,其模式部分將控制這動作部分的輸入,只有符合模式條件的記錄才可以交由動作部分基礎處理,而模式部分不僅可以寫成正則表達式(如上面的例子),awk還支持條件表達式,如:
/> awk '$3 < 4000 {print}' employees
Sally Chang 1654 7/22/54 650000
Billy Black 1683 9/23/44 336500
在花括號內,用分號分隔的語句稱為動作。如果模式在動作前面,模式將決定什么時候發出動作。動作可以是一個語句或是一組語句。語句之間用分號分隔,也可以用換行符,如:
pattern { action statement; action statement; etc. } or
pattern {
action statement
action statement
}
模式和動作一般是捆綁在一起的。需要注意的是,動作是花括號內的語句。模式控制的動作是從第一個左花括號開始到第一個右花括號結束,如下:
/> awk '$3 < 4000 && /Sally/ {print}' employees
Sally Chang 1654 7/22/54 650000
4. 匹配操作符:
" ~ " 用來在記錄或者域內匹配正則表達式。
/> awk '$1 ~ /[Bb]ill/' employees #顯示所有第一個域匹配Bill或bill的行。
Billy Black 1683 9/23/44 336500
/> awk '$1 !~ /[Bb]ill/' employees #顯示所有第一個域不匹配Bill或bill的行,其中!~表示不匹配的意思。
Tom Jones 4424 5/12/66 543354
Mary Adams 5346 11/4/63 28765
Sally Chang 1654 7/22/54 650000
5. awk的基本應用實例:
/> cat testfile
northwest NW Charles Main 3.0 .98 3 34
western WE Sharon Gray 5.3 .97 5 23
southwest SW Lewis Dalsass 2.7 .8 2 18
southern SO Suan Chin 5.1 .95 4 15
southeast SE Patricia Hemenway 4.0 .7 4 17
eastern EA TB Savage 4.4 .84 5 20
northeast NE AM Main Jr. 5.1 .94 3 13
north NO Margot Weber 4.5 .89 5 9
central CT Ann Stephens 5.7 .94 5 13
/> awk '/^north/' testfile #打印所有以north開頭的行。
northwest NW Charles Main 3.0 .98 3 34
northeast NE AM Main Jr. 5.1 .94 3 13
north NO Margot Weber 4.5 .89 5 9
/> awk '/^(no|so)/' testfile #打印所有以so和no開頭的行。
northwest NW Charles Main 3.0 .98 3 34
southwest SW Lewis Dalsass 2.7 .8 2 18
southern SO Suan Chin 5.1 .95 4 15
southeast SE Patricia Hemenway 4.0 .7 4 17
northeast NE AM Main Jr. 5.1 .94 3 13
north NO Margot Weber 4.5 .89 5 9
/> awk '$5 ~ /\.[7-9]+/' testfile #第五個域字段匹配包含.(點),后面是7-9的數字。
southwest SW Lewis Dalsass 2.7 .8 2 18
central CT Ann Stephens 5.7 .94 5 13
/> awk '$8 ~ /[0-9][0-9]$/{print $8}' testfile #第八個域以兩個數字結束的打印。
34
23
18
15
17
20
13
十. awk表達式功能:
1. 比較表達式:
比較表達式匹配那些只在條件為真時才運行的行。這些表達式利用關系運算符來比較數字和字符串。見如下awk支持的條件表達式列表:
運算符 | 含義 | 例子 |
< | 小於 | x < y |
<= | 小於等於 | x <= y |
== | 等於 | x == y |
!= | 不等於 | x != y |
>= | 大於等於 | x >= y |
> | 大於 | x > y |
~ | 匹配 | x ~ /y/ |
!~ | 不匹配 | x !~ /y/ |
/> cat employees
Tom Jones 4424 5/12/66 543354
Mary Adams 5346 11/4/63 28765
Sally Chang 1654 7/22/54 650000
Billy Black 1683 9/23/44 336500
/> awk '$3 == 5346' employees #打印第三個域等於5346的行。
Mary Adams 5346 11/4/63 28765
/> awk '$3 > 5000 {print $1}' employees #打印第三個域大於5000的行的第一個域字段。
Mary
/> awk '$2 ~ /Adam/' employess #打印第二個域匹配Adam的行。
Mary Adams 5346 11/4/63 28765
2. 條件表達式:
條件表達式使用兩個符號--問號和冒號給表達式賦值: conditional expression1 ? expression2 : expressional3,其邏輯等同於C語言中的條件表達式。其對應的if/else語句如下:
{
if (expression1)
expression2
else
expression3
}
/> cat testfile
northwest NW Charles Main 3.0 .98 3 34
western WE Sharon Gray 5.3 .97 5 23
southwest SW Lewis Dalsass 2.7 .8 2 18
southern SO Suan Chin 5.1 .95 4 15
southeast SE Patricia Hemenway 4.0 .7 4 17
eastern EA TB Savage 4.4 .84 5 20
northeast NE AM Main Jr. 5.1 .94 3 13
north NO Margot Weber 4.5 .89 5 9
central CT Ann Stephens 5.7 .94 5 13
/> awk 'NR <= 3 {print ($7 > 4 ? "high "$7 : "low "$7) }' testfile
low 3
high 5
low 2
3. 數學表達式:
運算可以在模式內進行,其中awk將所有的運算都視為浮點運算,見如下列表:
運算符 | 含義 | 例子 |
+ | 加 | x + y |
- | 減 | x - y |
* | 乘 | x * y |
/ | 除 | x / y |
% | 取余 | x % y |
^ | 乘方 | x ^ y |
/> awk '/southern/{print $5 + 10}' testfile #如果記錄包含正則表達式southern,第五個域就加10並打印。
15.1
/> awk '/southern/{print $8 /2 }' testfile #如果記錄包含正則表達式southern,第八個域除以2並打印。
7.5
4. 邏輯表達式:
見如下列表:
運算符 | 含義 | 例子 |
&& | 邏輯與 | a && b |
|| | 邏輯或 | a || b |
! | 邏輯非 | !a |
/> awk '$8 > 10 && $8 < 17' testfile #打印出第八個域的值大於10小於17的記錄。
southern SO Suan Chin 5.1 .95 4 15
central CT Ann Stephens 5.7 .94 5 13
#打印第二個域等於NW,或者第一個域匹配south的行的第一、第二個域。
/> awk '$2 == "NW" || $1 ~ /south/ {print $1,$2}' testfile
northwest NW
southwest SW
southern SO
southeast SE
/> awk '!($8 > 13) {print $8}' testfile #打印第八個域字段不大於13的行的第八個域。
3
9
13
5. 范圍模板:
范圍模板匹配從第一個模板的第一次出現到第二個模板的第一次出現,第一個模板的下一次出現到第一個模板的下一次出現等等。如果第一個模板匹配而第二個模板沒有出現,awk就顯示到文件末尾的所有行。
/> awk '/^western/,/^eastern/ {print $1}' testfile #打印以western開頭到eastern開頭的記錄的第一個域。
western WE
southwest SW
southern SO
southeast SE
eastern EA
6. 賦值符號:
#找到第三個域等於Ann的記錄,然后給該域重新賦值為Christian,之后再打印輸出該記錄。
/> awk '$3 == "Ann" { $3 = "Christian"; print}' testfile
central CT Christian Stephens 5.7 .94 5 13
/> awk '/Ann/{$8 += 12; print $8}' testfile #找到包含Ann的記錄,並將該條記錄的第八個域的值+=12,最后再打印輸出。
25