AWK :Linux 管理員的智能工具包

您正在學習 Linux 嗎?本文對於非常有用的 AWK 文本操作工具進行了介紹,非常有價值。

AWK 實用工具帶有其自己的自包含語言,它不僅是 Linux 中也是任何環境中現有的功能最強大的數據處理引擎之一。這種編程及數據操作語言(其名稱得自於它的創始人 Alfred Aho 、 Peter Weinberger 和 Brian Kernighan 姓氏的首個字母)的最大功能取決於一個人所擁有的知識。它允許您創建簡短的程序,這些程序讀取輸入文件、爲數據排序、處理數據、對輸入執行計算以及生成報表,還有無數其他的功能。

AWK 是什麼?

最簡單地說, AWK 是一種用於處理文本的編程語言工具。 AWK 實用工具的語言在很多方面類似於 shell 編程語言,儘管 AWK 具有完全屬於其本身的語法。在最初創造 AWK 時,其目的是用於文本處理,並且這種語言的基礎是,只要在輸入數據中有模式匹配,就執行一系列指令。該實用工具掃描文件中的每一行,查找與命令行中所給定內容相匹配的模式。如果發現匹配內容,則進行下一個編程步驟。如果找不到匹配內容,則繼續處理下一行。

儘管操作可能會很複雜,但命令的語法始終是:

awk '{pattern + action}' {filenames}

其中 pattern 表示 AWK 在數據中查找的內容,而 action 是在找到匹配內容時所執行的一系列命令。花括號 ({}) 不需要在程序中始終出現,但它們用於根據特定的模式對一系列指令進行分組。

瞭解字段

實用工具將每個輸入行分爲記錄和字段。 記錄 是單行的輸入,而每條記錄包含若干字段。默認的字段分隔符是空格或製表符,而記錄的分隔符是換行。雖然在默認情況下將製表符和空格都看作字段分隔符(多個空格仍然作爲一個分隔符),但是可以將分隔符從空格改爲任何其它字符。

爲了進行演示,請查看以下保存爲 emp_names 的員工列表文件:

46012 DULANEY EVAN MOBILE AL

46013 DURHAM JEFF MOBILE AL

46015 STEEN BILL MOBILE AL

46017 FELDMAN EVAN MOBILE AL

46018 SWIM STEVE UNKNOWN AL

46019 BOGUE ROBERT PHOENIX AZ

46021 JUNE MICAH PHOENIX AZ

46022 KANE SHERYL UNKNOWN AR

46024 WOOD WILLIAM MUNCIE IN

46026 FERGUS SARAH MUNCIE IN

46027 BUCK SARAH MUNCIE IN

46029 TUTTLE BOB MUNCIE IN

當 AWK 讀取輸入內容時,整條記錄被分配給變量 $0 。每個字段以字段分隔符分開,被分配給變量 $1 、 $2 、 $3 等等。一行在本質上可以包含無數個字段,通過字段號來訪問每個字段。因此,命令

awk '{print $1,$2,$3,$4,$5}' names

將會產生的打印輸出是

46012 DULANEY EVAN MOBILE AL

46013 DURHAM JEFF MOBILE AL

46015 STEEN BILL MOBILE AL

46017 FELDMAN EVAN MOBILE AL

46018 SWIM STEVE UNKNOWN AL

46019 BOGUE ROBERT PHOENIX AZ

46021 JUNE MICAH PHOENIX AZ

46022 KANE SHERYL UNKNOWN AR

46024 WOOD WILLIAM MUNCIE IN

46026 FERGUS SARAH MUNCIE IN

46027 BUCK SARAH MUNCIE IN

46029 TUTTLE BOB MUNCIE IN

值得注意的一項重要內容是, AWK 解釋由空格分隔的五個字段,但當它打印顯示內容時,在每個字段間只有一個空格。利用爲每個字段指定了唯一號碼的功能,您可以選擇只打印特定的字段。例如,只打印每條記錄的姓名時,只需選擇第二個和第三個字段進行打印:

$ awk '{print $2,$3}' emp_names

DULANEY EVAN

DURHAM JEFF

STEEN BILL

FELDMAN EVAN

SWIM STEVE

BOGUE ROBERT

JUNE MICAH

KANE SHERYL

WOOD WILLIAM

FERGUS SARAH

BUCK SARAH

TUTTLE BOB

$

您還可以指定按任何順序打印字段,而無論它們在記錄中是如何存在的。因此,只需要顯示姓名字段,並且使其順序顛倒,先顯示名字再顯示姓氏:

$ awk '{print $3,$2}' emp_names

EVAN DULANEY

JEFF DURHAM

BILL STEEN

EVAN FELDMAN

STEVE SWIM

ROBERT BOGUE

MICAH JUNE

SHERYL KANE

WILLIAM WOOD

SARAH FERGUS

SARAH BUCK

BOB TUTTLE

$

使用模式

通過包含一個必須匹配的模式,您可以選擇只對特定的記錄而不是所有的記錄進行操作。模式匹配的最簡單形式是搜索,其中要匹配的項目被包含在斜線 ( /pattern/ ) 中。例如,只對那些居住在阿拉巴馬州的員工執行前面的操作:

$ awk '/AL/ {print $3,$2}' emp_names

EVAN DULANEY

JEFF DURHAM

BILL STEEN

EVAN FELDMAN

STEVE SWIM

$

如果您不指定要打印的字段,則會打印整個匹配的條目:

$ awk '/AL/' emp_names

46012 DULANEY EVAN MOBILE AL

46013 DURHAM JEFF MOBILE AL

46015 STEEN BILL MOBILE AL

46017 FELDMAN EVAN MOBILE AL

46018 SWIM STEVE UNKNOWN AL

$

對同一數據集的多個命令可以用分號 ( ; ) 分隔開。例如,在一行中打印姓名,而在另一行中打印城市和州名:

$ awk '/AL/ {print $3,$2 ; print $4,$5}' emp_names

EVAN DULANEY

MOBILE AL

JEFF DURHAM

MOBILE AL

BILL STEEN

MOBILE AL

EVAN FELDMAN

MOBILE AL

STEVE SWIM

UNKNOWN AL

$

如果沒有使用分號 ( print $3,$2,$4,$5 ) ,則會在同一行中顯示所有內容。另一方面,如果分別給出兩個打印語句,則會產生完全不同的結果:

$ awk '/AL/ {print $3,$2} {print $4,$5}' emp_names

EVAN DULANEY

MOBILE AL

JEFF DURHAM

MOBILE AL

BILL STEEN

MOBILE AL

EVAN FELDMAN

MOBILE AL

STEVE SWIM

UNKNOWN AL

PHOENIX AZ

PHOENIX AZ

UNKNOWN AR

MUNCIE IN

MUNCIE IN

MUNCIE IN

MUNCIE IN

$

只有在列表中找到 AL 時纔會給出字段三和字段二。但是,字段四和字段五是無條件的,始終打印它們。只有第一組花括號中的命令對前面緊鄰的命令 ( /AL/ ) 起作用。

結果非常不便於閱讀,可以使其稍微更清晰一些。首先,在城市與州之間插入一個空格和逗號。然後,在每兩行顯示之後放置一個空行:

$ awk '/AL/ {print $3,$2 ; print $4", "$5"/n"}' emp_names

EVAN DULANEY

MOBILE , AL

JEFF DURHAM

MOBILE , AL

BILL STEEN

MOBILE , AL

EVAN FELDMAN

MOBILE , AL

STEVE SWIM

UNKNOWN, AL

$

在第四和第五個字段之間,添加一個逗號和一個空格(在引號之間),在第五個字段後面,打印一個換行符 ( /n ) 。在 AWK 打印語句中還可以使用那些可在 echo 命令中使用的所有特殊字符,包括:

  • /n (換行)
  • /t (製表)
  • /b (退格)
  • /f (進紙)
  • /r (回車)

因此,要讀取全部五個最初由製表符分隔開的字段,並且也利用製表符打印它們,您可以編程如下

$ awk '{print $1"/t"$2"/t"$3"/t"$4"/t"$5}' emp_names

46012 DULANEY EVAN MOBILE AL

46013 DURHAM JEFF MOBILE AL

46015 STEEN BILL MOBILE AL

46017 FELDMAN EVAN MOBILE AL

46018 SWIM STEVE UNKNOWN AL

46019 BOGUE ROBERT PHOENIX AZ

46021 JUNE MICAH PHOENIX AZ

46022 KANE SHERYL UNKNOWN AR

46024 WOOD WILLIAM MUNCIE IN

46026 FERGUS SARAH MUNCIE IN

46027 BUCK SARAH MUNCIE IN

46029 TUTTLE BOB MUNCIE IN

$

通過連續設置多項標準並用管道 ( | ) 符號將其分隔開,您可以一次搜索多個模式匹配:

$ awk '/AL|IN/' emp_names

46012 DULANEY EVAN MOBILE AL

46013 DURHAM JEFF MOBILE AL

46015 STEEN BILL MOBILE AL

46017 FELDMAN EVAN MOBILE AL

46018 SWIM STEVE UNKNOWN AL

46024 WOOD WILLIAM MUNCIE IN

46026 FERGUS SARAH MUNCIE IN

46027 BUCK SARAH MUNCIE IN

46029 TUTTLE BOB MUNCIE IN

$

這樣可找到每個阿拉巴馬州和印第安那州居民的匹配記錄。但是在試圖找出居住在亞利桑那州的人時,出現了一個問題:

$ awk '/AR/' emp_names

46019 BOGUE ROBERT PHOENIX AZ

46021 JUNE MICAH PHOENIX AZ

46022 KANE SHERYL UNKNOWN AZ

46026 FERGUS SARAH MUNCIE IN

46027 BUCK SARAH MUNCIE IN

$

員工 46026 和 46027 沒有住在亞利桑那州;但是他們的名字中包含所搜索的字符序列。切記,當在 AWK 中進行模式匹配時,例如 grep 、 sed 或者大部分其他 Linux/Unix 命令,將在記錄(行)中的任何位置查找匹配,除非指定進行其他操作。爲解決這一問題,必須將搜索與特定字段聯繫起來。通過利用代字號 (?) 以及對特定字段的說明,可以達到這一目的,如下例所示:

$ awk '$5 ? /AR/' emp_names

46019 BOGUE ROBERT PHOENIX AZ

46021 JUNE MICAH PHOENIX AZ

46022 KANE SHERYL UNKNOWN AZ

$

代字號(表示匹配)的對應符號是一個前面帶有感嘆號的代字號 (!?) 。這些字符通知程序,如果搜索序列沒有出現在指定字段中,則找出與搜索序列相匹配的所有行:

$ awk '$5 !? /AR/' names

46012 DULANEY EVAN MOBILE AL

46013 DURHAM JEFF MOBILE AL

46015 STEEN BILL MOBILE AL

46017 FELDMAN EVAN MOBILE AL

46018 SWIM STEVE UNKNOWN AL

46024 WOOD WILLIAM MUNCIE IN

46026 FERGUS SARAH MUNCIE IN

46027 BUCK SARAH MUNCIE IN

46029 TUTTLE BOB MUNCIE IN

$

在這種情況下,將顯示第五個字段中沒有 AR 的所有行 — 包括兩個 Sarah 條目,這兩個條目確實包含 AR ,但卻是在第三個字段而不是第五個字段中。

花括號和字段分隔符

括號字符在 AWK 命令中起着很重要的作用。出現在括號之間的操作指出將要發生什麼以及何時發生。當只使用一對括號時:

{print $3,$2}

括號間的所有操作同時發生。當使用多於一對的括號時:

{print $3}{print $2}

執行第一組命令,在該命令完成後執行第二組命令。注意以下兩列清單的區別:

$ awk '{print $3,$2}' names

EVAN DULANEY

JEFF DURHAM

BILL STEEN

EVAN FELDMAN

STEVE SWIM

ROBERT BOGUE

MICAH JUNE

SHERYL KANE

WILLIAM WOOD

SARAH FERGUS

SARAH BUCK

BOB TUTTLE

$

$ awk '{print $3}{print $2}' names

EVAN

DULANEY

JEFF

DURHAM

BILL

STEEN

EVAN

FELDMAN

STEVE

SWIM

ROBERT

BOGUE

MICAH

JUNE

SHERYL

KANE

WILLIAM

WOOD

SARAH

FERGUS

SARAH

BUCK

BOB

TUTTLE

$

要利用多組括號進行重複查找,執行第一組中的命令直到完成爲止;然後處理第二組命令。如果有第三組命令,則在第二組命令完成後執行它,以此類推。在所生成的打印輸出中,有兩個分隔的打印命令,因此先執行第一個命令,隨後執行第二個命令,這樣導致每個條目顯示在兩行而不是一行中。

區分兩個字段的字段分隔符不一定始終是空格;它可以是任何可識別的字符。爲進行演示,假定 emp_names 文件利用冒號而不是製表符來分隔字段:

$ cat emp_names

46012:DULANEY:EVAN: MOBILE : AL

46013: DURHAM :JEFF: MOBILE : AL

46015:STEEN:BILL: MOBILE : AL

46017:FELDMAN:EVAN: MOBILE : AL

46018:SWIM:STEVE:UNKNOWN: AL

46019:BOGUE:ROBERT: PHOENIX :AZ

46021:JUNE:MICAH: PHOENIX :AZ

46022:KANE:SHERYL:UNKNOWN:AR

46024:WOOD:WILLIAM: MUNCIE :IN

46026:FERGUS:SARAH: MUNCIE :IN

46027:BUCK:SARAH: MUNCIE :IN

46029:TUTTLE:BOB: MUNCIE :IN

$

如果試圖通過指定所需要的第二個字段來打印姓氏

$ awk '{print $2}' emp_names

您最後會得到十二個空行。因爲文件中沒有空格,除了第一個字段之外沒有可認別的字段。爲解決這一問題,必須通知 AWK 是空格之外的另一個字符作爲分隔符,有兩種方法可通知 AWK 使用新的字段分隔符:使用命令行參數 -F ,或在程序中指定變量 FS 。兩種方法的效果相同,只有一種例外情況,如下例所示:

$ awk '{FS=":"}{print $2}' emp_names

DURHAM

STEEN

FELDMAN

SWIM

BOGUE

JUNE

KANE

WOOD

FERGUS

BUCK

TUTTLE

$

$ awk -F: '{print $2}' emp_names

DULANEY

DURHAM

STEEN

FELDMAN

SWIM

BOGUE

JUNE

KANE

WOOD

FERGUS

BUCK

TUTTLE

$

在第一個命令中,頭一條記錄返回不正確的空行,而其他結果正確。直到讀取第二條記錄時,才識別字段分隔符並正確地執行。通過使用 BEGIN 語句可以糾正這一缺點(在後文詳述)。 -F 的功能非常類似於 BEGIN ,能夠正確地讀取第一條記錄並按要求執行。

在本文開始處我曾提到,默認的顯示 / 輸出字段分隔符是空格。通過使用輸出字段分隔符 ( OFS ) 變量,可以在程序中更改此特性。例如,要讀取文件(由冒號分隔)並以短劃線顯示,則命令是

$ awk -F":" '{OFS="-"}{print $1,$2,$3,$4,$5}' emp_names

46012-DULANEY-EVAN-MOBILE-AL

46013-DURHAM-JEFF-MOBILE-AL

46015-STEEN-BILL-MOBILE-AL

46017-FELDMAN-EVAN-MOBILE-AL

46018-SWIM-STEVE-UNKNOWN-AL

46019-BOGUE-ROBERT-PHOENIX-AZ

46021-JUNE-MICAH-PHOENIX-AZ

46022-KANE-SHERYL-UNKNOWN-AR

46024-WOOD-WILLIAM-MUNCIE-IN

46026-FERGUS-SARAH-MUNCIE-IN

46027-BUCK-SARAH-MUNCIE-IN

46029-TUTTLE-BOB-MUNCIE-IN

$

FS 和 OFS 是(輸入)字段分隔符和輸出字段分隔符,它們只是一對可以在 AWK 實用工具中使用的變量。例如,要在打印時爲每行編號,可以採用以下方式使用 NR 變量:

$ awk -F":" '{print NR,$1,$2,$3}' emp_names

1 46012 DULANEY EVAN

2 46013 DURHAM JEFF

3 46015 STEEN BILL

4 46017 FELDMAN EVAN

5 46018 SWIM STEVE

6 46019 BOGUE ROBERT

7 46021 JUNE MICAH

8 46022 KANE SHERYL

9 46024 WOOD WILLIAM

10 46026 FERGUS SARAH

11 46027 BUCK SARAH

12 46029 TUTTLE BOB

$

找出員工號碼處於 46012 和 46015 之間的所有行:

$ awk -F":" '/4601[2-5]/' emp_names

46012 DULANEY EVAN MOBILE AL

46013 DURHAM JEFF MOBILE AL

46015 STEEN BILL MOBILE AL

$

添加文本

可以按照添加控制序列或其他字符的相同方式將文本添加到顯示中。例如,要將分隔符從空格改爲冒號,則命令是

awk '{print $1":"$2":"$3":"$4":"$5}' emp_names > new_emp_names

在這種情況下,字符 ( : ) 包含在引號 ( "/" ) 中,它被添加到每個字段之間。在引號之間的值可以是任何內容。例如,創建一個關於居住在阿拉巴馬州的員工的外觀類似數據庫的顯示:

$ awk '$5 ~ /AL/ {print "NAME: "$2", "$3"/nCITY-STATE:

"$4", "$5"/n"}' emp_names

NAME: DULANEY, EVAN

CITY-STATE: MOBILE , AL

NAME: DURHAM , JEFF

CITY-STATE: MOBILE , AL

NAME: STEEN, BILL

CITY-STATE: MOBILE , AL

NAME: FELDMAN, EVAN

CITY-STATE: MOBILE , AL

NAME: SWIM, STEVE

CITY-STATE: UNKNOWN, AL

$

數學操作

AWK 除了提供文本功能,還提供全部範圍的算術操作符,包括以下符號:

+ 將數字相加
- 減
* 乘
/ 除
^ 執行指數運算
% 提供模
++ 將變量值加一
+= 將其他操作的結果分配給變量
— 將變量減一
-= 將減法操作的結果分配給變量
*= 分配乘法操作的結果
/= 分配除法操作的結果
%= 分配求模操作的結果

例如,假定您的機器上存在以下的文件,詳細地列出硬件商店中的物品:

$ cat inventory

hammers 5 7.99

drills 2 29.99

punches 7 3.59

drifts 2 4.09

bits 55 1.19

saws 123 14.99

nails 800 .19

screws 80 .29

brads 100 .24

$

第一項業務定單是通過將第二個字段(數量)的值乘以第三個字段(價格)的值,計算每種物品的庫存價值:

$ awk '{print $1,"QTY: "$2,"PRICE: "$3,"TOTAL: "$2*$3}' inventory

hammers QTY: 5 PRICE: 7.99 TOTAL: 39.95

drills QTY: 2 PRICE: 29.99 TOTAL: 59.98

punches QTY: 7 PRICE: 3.59 TOTAL: 25.13

drifts QTY: 2 PRICE: 4.09 TOTAL: 8.18

bits QTY: 55 PRICE: 1.19 TOTAL: 65.45

saws QTY: 123 PRICE: 14.99 TOTAL: 1843.77

nails QTY: 800 PRICE: .19 TOTAL: 152

screws QTY: 80 PRICE: .29 TOTAL: 23.2

brads QTY: 100 PRICE: .24 TOTAL: 24

$

如果這些行本身並不重要,您只是希望確定商店中有多少件物品,則可以分配一個普通變量,按照每條記錄中的物品數量增加:

$ awk '{x=x+$2} {print x}' inventory

5

7

14

16

71

194

994

1074

1174

$

根據這一數據,商店中有 1174 件物品。第一次執行時,變量 x 沒有值,因此它採用第一行第二個字段的值。第二次執行時,它保留了第一行的值並加上第二行的值,以此類推,直到達到累計的總合。

可以應用相同的過程來確定現有庫存的總價值:

$ awk '{x=x+($2*$3)} {print x}' inventory

39.95

99.93

125.06

133.24

198.69

2042.46

2194.46

2217.66

2241.66

$

因此, 1174 件物品的價值是 $2,241.66 。雖然這一過程可以獲得總計值,但它的外觀很差,需要加工成實際的報表。利用一些附加項,很容易使顯示變得更整潔:

$ awk '{x=x+($2*$3)}{print $1,"QTY: "$2,"PRICE: "$3,"TOTAL: "$2*$3,"BAL: "x}' inventory

hammers QTY: 5 PRICE: 7.99 TOTAL: 39.95 BAL: 39.95

drills QTY: 2 PRICE: 29.99 TOTAL: 59.98 BAL: 99.93

punches QTY: 7 PRICE: 3.59 TOTAL: 25.13 BAL: 125.06

drifts QTY: 2 PRICE: 4.09 TOTAL: 8.18 BAL: 133.24

bits QTY: 55 PRICE: 1.19 TOTAL: 65.45 BAL: 198.69

saws QTY: 123 PRICE: 14.99 TOTAL: 1843.77 BAL: 2042.46

nails QTY: 800 PRICE: .19 TOTAL: 152 BAL: 2194.46

screws QTY: 80 PRICE: .29 TOTAL: 23.2 BAL: 2217.66

brads QTY: 100 PRICE: .24 TOTAL: 24 BAL: 2241.66

$

該過程提供了每條記錄的清單,同時將總價值分配給庫存值,並保持商店資產的運作平衡。

BEGIN END

使用 BEGIN 和 END 語句可以分別指定在處理實際開始之前或者完成之後進行操作。 BEGIN 語句最常用於建立變量或顯示標題。另一方面, END 語句可用於在程序結束後繼續進行處理。

在前面的示例中,利用以下例程生成了物品的總價值:

awk '{x=x+($2*$3)} {print x}' inventory

該例程在運行總計累加時顯示了文件中的每一行。沒有其他方法可以指定它,而不讓在每一行進行打印也導致它始終不打印出來。但是,利用 END 語句可以避免這一問題:

$ awk '{x=x+($2*$3)} END {print "Total Value of Inventory:"x}' inventory

Total Value of Inventory: 2241.66

$

定義了變量 x ,它對每一行進行處理;但是,在所有處理完成之前不會生成顯示。儘管可以作爲獨立例程使用,它也可以置入到先前的代碼列表,添加更多信息並生成更完整的報表:

$ awk '{x=x+($2*$3)} {print $1,"QTY: "$2,"PRICE:

"$3,"TOTAL: "$2*$3} END {print "Total Value of Inventory: " x}' inventory

hammers QTY: 5 PRICE: 7.99 TOTAL: 39.95

drills QTY: 2 PRICE: 29.99 TOTAL: 59.98

punches QTY: 7 PRICE: 3.59 TOTAL: 25.13

drifts QTY: 2 PRICE: 4.09 TOTAL: 8.18

bits QTY: 55 PRICE: 1.19 TOTAL: 65.45

saws QTY: 123 PRICE: 14.99 TOTAL: 1843.77

nails QTY: 800 PRICE: .19 TOTAL: 152

screws QTY: 80 PRICE: .29 TOTAL: 23.2

brads QTY: 100 PRICE: .24 TOTAL: 24

Total Value of Inventory: 2241.66

$

BEGIN 命令與 END 的工作方式相同,但它建立了那些需要在完成其他工作之前所做的項目。該過程最常見的目的是創建報表的標題。此例程的語法類似於

$ awk 'BEGIN {print "ITEM QUANTITY PRICE TOTAL"}'

輸入、輸出和源文件

AWK 工具可以從文件中讀取其輸入,正如在此之前所有示例所做的那樣,它也可以從其他命令的輸出中獲取輸入。例如:

$ sort emp_names | awk '{print $3,$2}'

awk 命令的輸入是排序操作的輸出。除了 sort ,還可以使用任何其他的 Linux 命令 — 例如 grep 。該過程允許您在離開所選定字段前對文件執行其他操作。

類似於解釋程序, AWK 使用輸出改向操作符 > 和 >> 將其輸出放入文件中而不是標準輸出設備。這些符號的作用類似於它們在解釋程序中的對應符號,因此 > 在不存在文件時創建文件,而 >> 追加到現有文件的尾部。請看以下的示例:

$ awk '{print NR, $1 ) > "/tmp/filez" }' emp_names

$ cat /tmp/filez

1 46012

2 46013

3 46015

4 46017

5 46018

6 46019

7 46021

8 46022

9 46024

10 46026

11 46027

12 46029

$

檢查該語句的語法,您會看到輸出改向是在打印語句完成後進行的。必須將文件名包含在引號中,否則它只是一個未初始化的 AWK 變量,而將指令聯接起來會在 AWK 中產生錯誤。(如果不正確地使用改向符號,則 AWK 無法瞭解該符號意味着 “ 改向 ” 還是一個關係操作符。)

在 AWK 中輸出到管道也類似於解釋程序中所實現的相同操作。要將打印命令的輸出發送到管道中,可以在打印命令後附加管道符號以及命令的名稱,如下所示:

$ awk '{ print $2 | "sort" }' emp_names

BOGUE

BUCK

DULANEY

DURHAM

FELDMAN

FERGUS

JUNE

KANE

STEEN

SWIM

TUTTLE

WOOD

$

這是輸出改向的情況,必須將命令包含在引號中,而管道的名稱是被執行命令的名稱。

AWK 所使用的命令可以來自兩個地方。首先,可以在命令行中指定它們,如示例中所示。其次,它們可以由源文件提供。如果是這種情況,通過 -f 選項將這種情況向 AWK 發出警告。演示如下:

$ cat awklist

{print $3,$2}

{print $4,$5,"/n"}

$

$ awk -f awklist emp_names

EVAN DULANEY

MOBILE AL

JEFF DURHAM

MOBILE AL

BILL STEEN

MOBILE AL

EVAN FELDMAN

MOBILE AL

STEVE SWIM

UNKNOWN AL

ROBERT BOGUE

PHOENIX AZ

MICAH JUNE

PHOENIX AZ

SHERYL KANE

UNKNOWN AR

WILLIAM WOOD

MUNCIE IN

SARAH FERGUS

MUNCIE IN

SARAH BUCK

MUNCIE IN

BOB TUTTLE

MUNCIE IN

$

注意,在源文件中的任何地方或者在命令行中調用它時,不使用單引號。單引號只用於區別命令行中的命令與文件名稱。

如果簡單的輸出不能處理您的程序中所需要的複雜信息,則可以嘗試由 printf 命令獲得的更加複雜的輸出,其語法是

printf( format, value, value ...)

該語法類似於 C 語言中的 printf 命令,而格式的規格是相同的。通過插入一項定義如何打印數值的規格,可以定義該格式。格式規格包含一個跟有字母的 % 。類似於打印命令, printf 不必包含在圓括號中,但是可以認爲使用圓括號是一種良好的習慣。

下表列出 printf 命令提供的各種規格。

規格

說明

%c

打印單個 ASCII 字符

%d

打印十進制數

%e

打印數字的科學計數表示

%f

打印浮點表示

%g

打印 %e 或 %f ;兩種方式都更簡短

%o

打印無符號的八進制數

s

打印 ASCII 字符串

%x

打印無符號的十六進制數

%%

打印百分號;不執行轉換

可以在 % 與字符之間提供某些附加的格式化參數。這些參數進一步改進數值的打印方式:

參數

說明

-

將字段中的表達式向左對齊

,width

根據需要將字段補齊到指定寬度(前導零使用零將字段補齊)

.prec

小數點右面數字的最大字符串寬度或最大數量

 

printf 命令能夠控制並將數值從一種格式轉換爲另一種格式。當需要打印變量的值時,只需提供一種規格,指示 printf 如何打印信息(通常包含在雙引號中)即可。必須爲每個傳遞到 printf 的變量包含一個規格參數;如果包含過少的參數,則 printf 不會打印所有的數值。

處理錯誤

AWK 工具報告所發生錯誤的方式很令人惱火。一個錯誤會阻礙任何操作的進行,所提供的錯誤信息非常含混不清:

awk: syntax error near line 2

awk: bailing out near line 2

您可能會花幾小時的時間查看第 2 行,試圖找出它爲什麼阻礙程序運行;這就是支持使用源文件的一個有力論據。

切記有兩條規則可以幫助您避免出現語法錯誤:

1. 確保命令位於括號中,而括號位於單引號中。沒有使用這些字符之一必然導致程序無法運行。

2. 搜索命令需要位於斜線之間。要找出住在印第安那州的員工,您必須使用 “ /IN/ ” 而不是 “ IN ” 。

結論

儘管 AWK 完全代表另外的含意,但它應該是管理員智能工具包的首字母縮寫。連同 SED 一起, AWK 實用工具是 Linux 管理員所擁有的功能最強大和靈活的工具之一。通過了解其語言的一些特性,您可以開闢出能夠簡化任務的領域,否則這些任務將會是非常費時和困難的。

Emmett Dulaney ( [email protected] ) 獲得了 18 種供應商認證。他編寫了數本關於 Linux 、 UNIX 和認證研究的書籍,並在許多會議上進行了演講,而且他是 Mercury Technical Solutions 的前合作伙伴。

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