跳轉到內容

Awk 入門/Awk 程式檔案

來自 Wikibooks,開放書籍,開放世界

有時 Awk 程式需要反覆使用。在這種情況下,從 shell 指令碼執行 Awk 程式非常簡單。例如,考慮一個將檔案中的每個單詞列印在單獨一行的 Awk 指令碼。這可以使用名為“words”的指令碼完成,其中包含

   awk '{c=split($0, s); for(n=1; n<=c; ++n) print s[n] }' $1

然後可以使“Words”可執行(使用“chmod +x words”),並像任何其他命令一樣呼叫生成的 shell“程式”。例如,

“words”可以從“vi”文字編輯器中呼叫,如下所示

   :%!words

這會將所有文字變成一個單字列表。

  • 再舉一個例子,考慮前面提到的雙倍行距程式。這可以稍微更改以接受標準輸入,使用前面描述的“-”,然後複製到名為“double”的檔案中
   awk '{print; if (NF != 0) print ""}' -

—然後可以從“vi”呼叫它來對編輯器中的所有文字進行雙倍行距。

  • 下一步將是允許“double”執行相反的操作:將雙倍行距檔案恢復為單倍行距,使用選項
   undouble

當然,任務的第一部分是設計一種方法來刪除多餘的空行,而不透過刪除所有空行來破壞原始單倍行距檔案的間距。最簡單的方法是刪除連續空行塊中的每隔一行。這並不一定能保留原始間距,但它會以某種形式保留間距。

實現此方法也很簡單,涉及使用名為“skip”的變數。每當跳過空行時,此變數被設定為“1”,以告訴 Awk 程式不要跳過下一行。方案如下

   BEGIN {set skip to 0}
   scan the input:
      if skip == 0    if line is blank
                         skip = 1
                      else
                         print the line
                      get next line of input
      if skip == 1    print the line
                      skip = 0
                      get next line of input

這直接轉換為以下 Awk 程式

   BEGIN      {skip = 0}
   skip == 0  {if (NF == 0) 
                {skip = 1} 
               else 
                {print}; 
               next}
   skip == 1  {print; 
               skip = 0;
               next}

該程式可以放在一個單獨的檔案中,命名為“undouble.awk”,並編寫 shell 指令碼“undouble”為

   awk -f undouble.awk

它也可以直接嵌入到 shell 指令碼中,使用單引號將程式括起來,並使用反斜槓(“\”)允許多行

   awk 'BEGIN      {skip = 0} \
        skip == 0  {if (NF == 0) 
                     {skip = 1}  \
                    else 
                     {print};  \
                    next} \
        skip == 1  {print; \
                    skip = 0; \
                    next}'

請記住,當使用“\”將 Awk 程式嵌入到指令碼檔案中時,該程式在 Awk 中顯示為一行。必須使用分號分隔命令。

再舉一個更復雜的例子,我遇到一個問題,當我編寫文字文件時,有時我會意外地輸入兩次同一個詞:“結果也是也是那樣......”。這些重複的詞在校對時很難發現,但編寫一個 Awk 程式來完成這項工作很簡單,它掃描文字檔案以查詢重複項;如果找到重複項,則列印重複的詞和它所在的行;否則列印“未找到重複項”。

   BEGIN { dups=0; w="xy-zzy" }
         { for( n=1; n<=NF; n++) 
              { if ( w == $n ) { print w, "::", $0 ; dups = 1 } ; w = $n }
         } 
   END   { if (dups == 0) print "No duplicates found." }

“w”變數儲存檔案中每個詞,將其與檔案中的下一個詞進行比較;w 被初始化為“xy-zzy”,因為這不太可能是檔案中的一個詞。變數“dup”被初始化為 0,如果找到重複項則設定為 1;如果在結尾時仍然為 0,則程式列印“未找到重複項”訊息。與前面的示例一樣,我們可以將其放入一個單獨的檔案中,或者將其嵌入到指令碼檔案中。

  • 最後這些示例使用變數來允許 Awk 程式跟蹤它一直在做什麼。如前所述,Awk 以迴圈方式執行:獲取一行,處理它,獲取下一行,處理它,等等;為了使 Awk 程式記住迴圈之間的內容,它需要在變數中留下一個便條。

例如,假設我們要匹配第一欄位值為 1,000 的行,但隨後列印下一行。我們可以這樣做:

   BEGIN        {flag = 0}
   $1 == 1000   {flag = 1; 
                 next}
   flag == 1    {print; 
                 flag = 0;
                 next}

該程式在找到以 1,000 開頭的行時設定一個名為“flag”的變數,然後獲取下一行輸入。列印下一行輸入,然後清除“flag”,以便下一行不會被列印。

如果我們想列印接下來的行,我們可以使用一個名為“counter”的變數以幾乎相同的方式做到這一點

   BEGIN         {counter = 0}
   $1 == 1000    {counter = 5;
                  next}
   counter > 0   {print; 
                  counter--;
                  next}

該程式在找到以 1,000 開頭的行時將名為“counter”的變數初始化為 5;對於接下來的 5 行輸入,它列印它們並將“counter”遞減,直到它為零。

這種方法可以根據需要進行擴充套件。假設我們有一個輸入五行的五種不同操作的列表,要在匹配一行輸入後執行;然後我們可以建立一個名為“state”的變數,它儲存接下來要執行的列表中的哪個專案。該方案通常如下

   BEGIN {set state to 0}
   scan the input:
      if match        set state to 1
                      get next line of input
      if state == 1   do the first thing in the list
                      state = 2
                      get next line of input
      if state == 2   do the second thing in the list
                      state = 3
                      get next line of input
      if state == 3   do the third thing in the list
                      state = 4
                      get next line of input
      if state == 4   do the fourth thing in the list
                      state = 5
                      get next line of input
      if state == 5   do the fifth (and last) thing in the list
                      state = 0
                      get next line of input

這被稱為“狀態機”。在這種情況下,它正在執行一個簡單的操作列表,但相同的方法也可以用於執行更復雜的動作分支序列,就像我們在流程圖中而不是簡單的列表中可能遇到的那樣。

我們可以將狀態號分配給流程圖中的塊,然後使用 if-then 測試來設定狀態變數,以指示接下來應該執行哪個備用操作。但是,很少有 Awk 程式需要如此複雜,在這裡介紹更詳細的示例可能會比它值得的更令人困惑。需要記住的重要一點是,awk 程式可以在一行掃描迴圈中在變數中給自己留言,以告訴它在以後的行掃描迴圈中該做什麼。

華夏公益教科書