12-4 Awk
命令稿
內容:
當一行命令敘述無法完成任務時,則可考慮將 awk
的搜尋與動作編寫成一個命令稿,再以批次執行方式處理,也許較容易達成目的。Awk
命令稿執行方式如下:
$ awk –f script_file
input_file |
其中
script_file
為檢索
input_file
檔案的命令稿,大部分
awk
搜尋與動作敘述都可被編寫入。檢索處理後的結果將會顯示在螢幕上,也可將它轉向輸出到其他檔案上(如
> output_file)。
12-4-1 awk
命令稿格式
某一公司的員工資料檔案(employee)包含有員工姓名、電話、時薪與工作時數,我們可利用此檔案來簡略說明
awk
命令稿的編寫方式。
【A.
Awk
範例一】
編寫一個命令稿(list.awk,檔案名稱與型態可以任意命名),其功能是列印出
employee
檔案內的所有資料;處理資料之前先印出一行各欄位的名稱(BEGIN),再一筆接一筆連續印出內容;命令稿的內容及執行結果如下:
[tsnien@Linux-1 tools]$ cat list.awk
BEGIN {
print "姓名",
"\t", "電話",
"\t\t", "時薪",
"\t", "時數"
}
{ print $1, "\t", $2,
"\t", $3, "\t", $4 }
[tsnien@Linux-1 tools]$ awk -f list.awk employee
姓名
電話
時薪
時數
Frank 07-234567
412.0 25
George 04-384123
217.0 18
Nacy 06-672314
516.0 45
Louis 07-384675
311.0 32
Eva 04-243890
358.5 38
Tank 06-631289
482.5 42 |
我們可以看出基本命令稿的語法幾乎與命令行語法相同,唯一不同的是不必用兩個單引號(’
…’)包起來。此程式的執行步驟如下:
(1)
步驟
1:還未讀取輸入檔案之前,首先執行
BEGIN
敘述,也就是印出姓名、電話、時薪與時數等字串。
(2)
步驟
2:讀取檔案內一行資料(即是一筆資料),並依照欄位位置將其內容填入
$1、$2、$3
與
$4 變數內。
(3)
步驟
3:
awk
敘述中沒有搜尋條件,表示每一筆資料都必須依照後面指定動作執行,亦即印出各變數內容(print
…)。
(4)
步驟
4:如果檔案內還有下一筆資料,則回到步驟
2
繼續執行,否則結束讀取檔案,並執行 END
敘述內容(本範例沒有 END)。
【B.
Awk
範例二】
搜尋並印出電話在高雄的員工資料,命令稿(find.awk)與執行結果如下:
[tsnien@Linux-1 tools]$ cat find.awk
/07-/ {print}
[tsnien@Linux-1 tools]$ awk -f find.awk employee
Frank 07-234567
412.0 25
Louis 07-384675
311.0 32 |
【C.
Awk
範例三】
印出工作時數超過
30
小時員工的姓名、時薪與工作時數,命令稿(time.awk)與執行結果如下:
[tsnien@Linux-1 tools]$ cat time.awk
$4 >= 30 {print $1,
"\t", $3, "\t", $4}
[tsnien@Linux-1 tools]$ awk -f time.awk employee
Nacy 516.0 45
Louis 311.0 32
Eva 358.5 38
Tank 482.5 42 |
本範例執行動作如下:當
awk
讀入每一資料後,首先判斷 $4(第四欄位,即是工作時數)是否超過
30,如果是則印出欄位
1、3、4
的內容;接著再讀取下一筆,直到檔案內全部讀完為止。
【D.
Awk
範例四】
計算出本月每一員工的應領薪資,以及全部薪資總額,命令稿(total.awk)及操作範例如下:
[tsnien@Linux-1 tools]$ cat total.awk
BEGIN {print "Name",
"\t", "Payment"}
{
payment = $3 * $4
print $1, "\t", payment
total = total + payment
}
END {print "Total
payment = ", total}
[tsnien@Linux-1 tools]$ awk -f total.awk employee
Name Payment
Frank 10300
George 3906
Nacy 23220
Louis 9952
Eva 13623
Tank 20265
Total payment = 81266 |
簡略說明
total.awk
的運作方式,還未讀取輸入檔案(employee)之前,先印出一行’Name’與’Payment’字樣(BEGIN
敘述)。接著按照輸入檔案內資料的排列次序,每次讀入一筆記錄,並計算個人薪資(payment
= $3 * $4),以及印出員工姓名及個人薪資,再累積計算總共薪資(total
= total + payment)。輸入檔案內資料讀取完畢,最後印出所有薪資的總合(END
敘述)。
【E.
Awk
範例五】
列出時薪超過
350
元的員工姓名與應領薪資,以及平均薪資多少,命令稿(hi-pay.awk)及執行結果如下:
[tsnien@Linux-1 tools]$ cat hi-pay.awk
BEGIN {print "Name",
"\t", "Payment"}
$3 >= 350 {
payment = $3 * $4
total = total +
payment
number = number +1
print $1, "\t",
payment
}
END {
average = total /
number
print "High payments
= ", number
print "Average
payment = ", average
}
[tsnien@Linux-1 tools]$ awk -f hi-pay.awk employee
Name Payment
Frank 10300
Nacy 23220
Eva 13623
Tank 20265
High payments = 4
Average payment = 16852 |
【F.
Awk
範例六】
印出時薪低於
400
元而且應領薪資低於 10000
元的員工姓名與應領薪資,並印出人數與其平均薪資多少。命令稿(lowpay.awk)及操作範例如下:
[tsnien@Linux-1 tools]$ cat lowpay.awk
BEGIN {
printf("Name\t
Payment\n");
}
($3 < 400) {
payment = $3 * $4;
if (payment < 10000)
{
total = total +
payment;
number = number
+1;
printf("%s\t
%d\n", $1, payment);
}
}
END {
printf("Low payments
= %d\n", number);
printf("Average
payment = %.2f\n", total / number);
}
[tsnien@Linux-1 tools]$ awk -f lowpay.awk employee
Name Payment
George 3906
Louis 9952
Low payments = 2
Average payment =
6929.00 |
由上述
lowpay.awk
範例可以看出,awk
動作敘述(action)幾乎與
C
語言的語法相同;不僅如此,其他控制敘述、函數宣告的語法,也幾乎相同,這對我們學習
awk
語法有相當的幫助。值得注意的是,awk
搜尋敘述包含許多文件處理的特殊語法(如正規式圖樣搜尋),因此保有自己獨特的語法,但也大多與其他過濾器工具(如
grep 或
sed)相似。
12-4-2 Awk
控制敘述
Awk
控制敘述的語法幾乎與
C
語言相同,這對我們在學習上顯得格外容易,這裡用幾個範例來說明各種控制敘述的使用方法。以下各個範例使用一個輸入檔案(course
檔案),檔案中每一筆資料(每一行)表示學生的姓名、英文、數學、程式設計、作業系統與資料結構的成績(由左到右依序排列),內容如下所示:
[tsnien@Linux-1 tools]$ cat course
Frank 60 70 90 80 73
George 50 40 60 70 72
Nacy 90 73 56 75 82
Louis 90 67 89 73 56
Eva 40 56 72 45 51
Tank 72 80 69 90 92 |
【A.
if
控制敘述】
if
條件敘述的語法如下:
if (expression)
action_1
[else
action_2]
|
如果
expression
條件判斷成立,則執行
action_1
敘述;否則執行
action_2
敘述,其中
else
敘述選項([…]),依照需求決定是否加入。我們利用一個範例(if.awk)來說明
if
敘述的使用方法,該程式可計算並輸出 course
檔案中每一個學生的平均分數,並標示是否及格(平均超過
70
分及格),命令稿(if.awk)與執行結果如下:
[tsnien@Linux-1 tools]$ cat if.awk
{
sum = $2 + $3 +$4 +
$5 +$6;
average = sum / 5;
if (average > 70)
grade = "Pass";
else
grade = "Fail";
printf("%s course =
%d and %s\n", $1, average, grade);
}
[tsnien@Linux-1 tools]$ awk -f if.awk course
Frank course = 74 and
Pass
George course = 58 and
Fail
Nacy course = 75 and
Pass
Louis course = 75 and
Pass
Eva course = 52 and
Fail
Tank course = 80 and
Pass |
在
if.awk
命令稿內並沒有搜尋條件,表示每一筆資料都必須處理。Awk
依序讀取每一筆資料,並計算其總合(sum)及平均分數(average),接著再判斷是否有超過
70
分。執行當中,awk
會依序讀完所有資料,因此無需指定多少筆記錄。
【B.
while
迴圈敘述】
while
迴圈語法如下:
條件
condition
成立則執行
action
部分。以下範例是計算並印出每一學生的學其平均分數,命令稿(while.awk)與操作結果如下:
[tsnien@Linux-1 tools]$ cat while.awk
{
sum = 0;
count = 2;
while (count <= NF)
{
sum = sum +
$count;
count++
}
average = sum /
(NF-1);
printf("%s average
= %d\n", $1, average);
}
[tsnien@Linux-1 tools]$ awk -f while.awk course
Frank average = 74
George average = 58
Nacy average = 75
Louis average = 75
Eva average = 52
Tank average = 80 |
動作敘述(action)部分如果超過一個敘述以上,則必須利用左右大括號包起來,這方面與
C 語言相同。
【C.
do
迴圈敘述】
do
迴圈敘述的語法如下:
do
action
while (condition) |
如同
while
迴圈的範例,如下:
[tsnien@Linux-1 tools]$ cat do.awk
{
sum = 0;
count = 2;
do {
sum = sum +
$count;
count++
}while(count <= NF);
average = sum /
(NF-1);
printf("%s average
= %d\n", $1, average);
}
[tsnien@Linux-1 tools]$ awk -f do.awk course
Frank average = 74
George average = 58
Nacy average = 75
Louis average = 75
Eva average = 52
Tank average = 80 |
【D.
for
迴圈敘述】
for
迴圈敘述的語法與
C
語言很類似,格式如下:
for (set_counter ;
test_counter ; calculate_counter)
action |
其中
set_counter
為設定計數器的初始值;test_counter
為設定一個測試條件,條件成立則執行迴圈內
action
敘述,執行後再依照
calculate_counter
方式計算計數器的內容,大多是遞增或遞減方式。每次執行完
for 迴圈內
action
敘述後,會再重新測試 test_counter,如果不成立的話,則離開並結束
for
迴圈執行。另外,action
如果超過一個敘述的話,則必須利用左右大括號包起來。範例如下:
[tsnien@Linux-1 tools]$ cat for.awk
# awk for-loop example
{
sum = 0;
for (count=2; count
<= NF; count++)
sum = sum +
$count;
average = sum /
(NF-1);
printf("%s average
= %d\n", $1, average);
}
[tsnien@Linux-1 tools]$ awk -f for.awk course
Frank average = 74
George average = 58
Nacy average = 75
Louis average = 75
Eva average = 52
Tank average = 80 |
【E.
break
與
continue
敘述】
我們可以利用
break 或
continue
敘述來改變
for、while
或
do
迴圈的正常運作,它們的語法大多與 C
語言相似,這裡就不再贅言了。
【F.
變數傳遞】
執行
awk
命令稿可區分為 BEGIN、action
與
END
三個程式區塊,其變數是可以相互引用的。以下範例是計算出
course
檔案內,該班及各科成績的平均值。首先在 BEGIN
區塊內設定變數,接著在 action
區塊內累計各科成績,最後再由
END
區塊內計算出各科成績的平均值(NR
為讀入記錄的筆數)。其命令稿(var.awk)與操作結果如下:
[tsnien@Linux-1
tools]$ cat var.awk
BEGIN {
eng=0; math=0; prog=0;
os=0; data=0;
}
{
eng = eng + $2;
math = math + $3;
prog = prog + $4;
os = os + $5;
data = data +$6;
}
END {
printf("英文
數學
程式設計
作業系統
資料結構\n");
printf("%d\t%d\t%d\t%d\t%d\n",
eng/NR, math/NR, prog/NR,
os/NR, data/NR);
}
[tsnien@Linux-1
tools]$ awk -f var.awk course
英文
數學
程式設計
作業系統
資料結構
67 64 72
72 71 |
|
翻轉工作室:粘添壽
Linux 伺服器系統管理 - CentOS:
翻轉電子書系列:
|