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

risingsunczl發表於2007-01-27

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

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

[@more@]

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 ( ) 獲得了 18 種供應商認證。他編寫了數本關於 Linux 、 UNIX 和認證研究的書籍,並在許多會議上進行了演講,而且他是 Mercury Technical Solutions 的前合作伙伴。

來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/653579/viewspace-894409/,如需轉載,請註明出處,否則將追究法律責任。

相關文章