跳轉到內容

Awk 入門/搜尋模式 (2)

來自華夏公益教科書,開放的書籍,用於開放的世界

欄位和塊

[編輯 | 編輯原始碼]

Awk 的字串搜尋功能還有更多內容。搜尋可以限制在輸入行中的單個欄位。例如

$1 ~ /^France$/

這將搜尋第一個欄位($1 - 稍後將詳細介紹“欄位變數”)是“France”的行,而

$1 !~ /^Norway$/

這將搜尋第一個欄位不是“Norway”的行。

可以使用一個搜尋模式匹配塊中的第一行,另一個搜尋模式匹配塊中的最後一行,來搜尋文字中的一系列或“塊”連續行。例如

/^Ireland/,/^Summary/

這將匹配第一行以“Ireland”開頭,最後一行以“Summary”開頭的文字塊。

工作原理如下:一旦匹配了/^Ireland/,所有後續的文字行將自動匹配,直到匹配了/^Summary/。此時,匹配停止。如果未找到以“Summary”開頭的行,則從“Ireland”之後的文字到檔案末尾的所有內容都將匹配。

超越正則表示式

[編輯 | 編輯原始碼]

搜尋模式不必是正則表示式。它也可以是各種其他表示式。例如

NR == 10

這將匹配第 10 行。從 1 開始對行進行編號。NR 如概述中所述,是 Awk 搜尋的行的計數,而 == 是“等於”運算子。類似地

NR == 10,NR == 20

這將匹配輸入檔案中的第 10 行到第 20 行。

比較運算子

[編輯 | 編輯原始碼]

Awk 支援使用全面的比較運算子進行搜尋模式

  • < 小於
  • <= 小於或等於
  • == 等於
  • != 不等於
  • >= 大於或等於
  • > 大於
  • ~ 匹配
  • !~ 不匹配

例如,

NF == 0

這將匹配所有空行,或欄位數為零的行。

$1 == "France"

這是一個字串比較,它將匹配第一個欄位是字串“France”的任何行。細心的讀者可能注意到,此示例似乎與上一個示例做的事情相同

$1 ~ /^France$/

實際上,這兩個示例都做著同樣的事情,但在上面的示例中,^$ 元字元必須用於正則表示式以指定與整個第一個欄位的匹配;如果沒有它們,它將匹配諸如“FranceFour”、“NewFrance”之類的字串。字串表示式只匹配“France”。

邏輯運算子

[編輯 | 編輯原始碼]

還可以使用 &&(AND)和 ||(OR)運算子組合多個搜尋模式。例如

((NR >= 30) && ($1 == "France")) || ($1 == "Norway")

這將匹配第 30 行之後的任何以“France”開頭的行,或任何以“Norway”開頭的行。如果一行以“France”開頭,但它在第 30 行之前,則它將不匹配。然而,所有以“Norway”開頭的行匹配。

上面未列出的一種模式匹配類別是對欄位變數執行數字比較。當然可以做到;例如

$1 == 100

這將匹配第一個欄位的數字值等於 100 的任何行。這很容易做到,並且可以正常工作。但是,假設我們要執行

$1 < 100

通常可以正常工作,但有一個棘手的問題,需要進行一些解釋:如果輸入的第一個欄位可以是數字或文字字串,則這種數字比較可能會產生瘋狂的結果,匹配一些與數字值不匹配的文字字串。

這是因為 Awk 是一種弱型別語言。它的變數可以儲存數字或字串,Awk 將對每個變數執行相應的操作。在上面的數字比較中,如果$1 包含數字值,Awk 將按預期對其執行數字比較;但如果$1 包含文字字串,Awk 將對$1 中的文字字串和三字母文字字串“100”執行文字比較。對於簡單地測試相等或不相等,這可以正常工作,因為數字和字串比較將產生相同的結果,但對於“小於”或“大於”比較,它將產生意外的結果。本質上,在比較字串時,Awk 會比較它們的 ASCII 值。這大致相當於按字母順序(“電話簿風格”)排序。即使如此,它也不是完全按字母順序排序,因為大寫和小寫字母將無法正確比較,數字和標點符號的比較方式有些隨意。

更多關於型別

[編輯 | 編輯原始碼]

Awk 並沒有壞掉;它只是按照指示在這個例子中這樣做。如果出現這個問題,可以向比較中新增第二個測試以確定欄位是否包含數字值或文字字串。第二個測試的形式為

(( $1 + 0 ) == $1 )

如果$1 包含數字值,則此表示式的左側將向其新增 0,Awk 將執行始終為真的數字比較。

如果 $1 包含看起來不像數字的文字字串,為了更好地做,Awk 將將其值解釋為 0。這意味著表示式的左側將計算為零;因為$1 中有一個非數字文字字串,所以 Awk 將執行始終為假的字串比較。這將導致更可行的比較

((( $1 + 0 ) == $1 ) && ( $1 > 100 ))

可以修改相同的測試來檢查文字字串而不是數字值

(( $1 + 0 ) != $1 )

值得記住這個技巧,以備不時之需。弱型別語言很方便,但在某些特殊情況下,它們可能會適得其反。

測試它

[編輯 | 編輯原始碼]

順便說一句,如果對 Awk 處理特定型別資料的方式存在疑問,只需執行測試即可確定。例如,我想看看我的 Awk 版本是否可以處理 C 中指定的十六進位制值 - 例如,“0xA8” - 所以我只需在命令提示符下輸入以下內容

awk 'BEGIN {tv="0xA8"; print tv,tv+0}'

這列印了“0xA8 0”,這意味著 Awk 認為資料嚴格來說是一個字串。這個小程式只包含一個 BEGIN 子句,允許在不指定輸入檔案的情況下執行 Awk 程式。這種“單行程式”在玩示例時很方便。如果你不確定 Awk 可能會做什麼,只需嘗試一下;它不會破壞任何東西。

  1. 編寫一個 Awk 程式,列印任何包含少於 5 個單詞的行,除非該行以星號開頭。
  2. 編寫一個 Awk 程式,列印每個以數字開頭的行。
  3. 編寫一個 Awk 程式,掃描帶行號的文字檔案以查詢錯誤。它應該打印出任何缺少行號的行,以及任何編號錯誤的行,以及實際的行號。

在下一頁中,您將瞭解字串和數字的一些更細微的方面。

華夏公益教科書