AWK 通過例子來介紹

AWK 是字串操作語言,主要用於 UNIX 系統。AWK 背後的想法是建立一種在處理檔案時使用的通用語言,這種語言並不太複雜,無法理解。

AWK 還有其他一些變體,但主要概念是相同的,只是附加功能。這些其他變體是 NAWK 和 GAWK。GAWK 包含兩者的所有功能,如果你願意,NAWK 比 AWK 高出一步。

想到 AWK 最簡單的方法是考慮它有兩個主要部分。模式和行動。

可能是 AWK 最基本的例子:(參見:Hello World)

BEGIN {print "START"}
      {print        }
END   {print "STOP" }

這裡,關鍵字 BEGINEND 是模式,而動作在{}內。這個例子沒用,但實際上只需要做一些小改動就可以使它成為一個有用的函式。

BEGIN {print "File\tAuthor"}
      {print $8, "\t", $3}
END {print " - DONE - "}

這裡,\t 表示 Tab 字元,用於平均輸出行邊界。 $ 8 和$ 3 類似於 Shell Scripts 中的使用,但它不使用第 3 和第 8 個引數,而是使用輸入行的第 3 和第 8 列。

因此,此示例將列印:檔案作者位於頂行,而第二行則處理檔案路徑。 $ 8 是檔案的名稱,$ 3 是所有者(當檢視目錄路徑時,這將更加清晰)。最後,底線將列印,如你所料 - 完成 -

以上示例的信用轉到 http://www.grymoire.com/Unix/Awk.html

參考檔案

來自 Greg Goebel 的 coins.txt

gold     1    1986  USA                 American Eagle
gold     1    1908  Austria-Hungary     Franz Josef 100 Korona
silver  10    1981  USA                 ingot
gold     1    1984  Switzerland         ingot
gold     1    1979  RSA                 Krugerrand
gold     0.5  1981  RSA                 Krugerrand
gold     0.1  1986  PRC                 Panda
silver   1    1986  USA                 Liberty dollar
gold     0.25 1986  USA                 Liberty 5-dollar piece
silver   0.5  1986  USA                 Liberty 50-cent piece
silver   1    1987  USA                 Constitution dollar
gold     0.25 1987  USA                 Constitution 5-dollar piece
gold     1    1988  Canada              Maple Leaf

最小的理論

一般 awk 單行:

awk <awk program> <file>

要麼:

<shell-command> | awk <awk program> 

<shell-command><file> 被稱為 awk 輸入

<awk program> 是此模板後面的程式碼(單個,不是雙引號):

'BEGIN   {<init actions>};
 <cond1> {<program actions>};
 <cond2> {<program actions>};
 ...
 END  {<final actions>}'

哪裡:

  • <condX> 條件通常是正規表示式/re/,與 awk 輸入行匹配;
  • <* actions>語句序列,類似於 shell 命令,配有類似 C 的結構。

``按照以下規則處理:

  1. BEGIN ...END ... 是可選的,在處理 awk 輸入行之前或之後執行。
  2. 對於 awk 輸入中的每一行,如果條件 <condN> 為 meat,則執行相關的 <program actions> 塊。
  3. {<program actions>} 預設為 {print $0}

條件可以與標準邏輯運算子組合:

    /gold/ || /USA/ && !/1986/

&& 優先於||;

Theprint 宣告print item1 item2 語句在 STDOUT 上列印專案。
專案可以是變數(X$0),字串(hello)或數字。
item1, item2OFS 變數的值進行整理;
item1 item2 剛剛好 ! 使用 item1 " " item2 作為空格或 printf 以獲得更多功能。

變數不需要 $,即:print myVar;
以下特殊變數內建於 awk 中:

  • FS:作為欄位分隔符來分割欄位中的 awk 輸入行。我可以成為一個單一的角色,FS="c"; 一個空字串,FS=""(然後每個單獨的字元變成一個單獨的欄位); 一個沒有斜線的正規表示式,FS="re"; FS=" " 代表空格和製表符的執行,是預設值。
  • NF:要讀取的欄位數;
  • $1$2,…:第 1 場,第 2 場。等當前輸入行,
  • $0:當前輸入線;
  • NR:當前放線號。
  • OFS:列印時用於整理欄位的字串。
  • ORS:輸出記錄分隔符,預設為換行符。
  • RS:輸入行(記錄)分隔符。預設為換行符。設為 FS
  • IGNORECASE:正則表達時影響 FS 和 RS;

例子

通過 regexp gold 過濾行並計算它們:

# awk 'BEGIN {print "Coins"} /gold/{i++; print $0}  END {print i " lines out of " NR}' coins.txt
Coins
gold     1    1986  USA                 American Eagle      
gold     1    1908  Austria-Hungary     Franz Josef 100 Korona 
gold     1    1984  Switzerland         ingot 
gold     1    1979  RSA                 Krugerrand 
gold     0.5  1981  RSA                 Krugerrand 
gold     0.1  1986  PRC                 Panda                       
gold     0.25 1986  USA                 Liberty 5-dollar piece
gold     0.25 1987  USA                 Constitution 5-dollar piece
gold     1    1988  Canada              Maple Leaf
9 lines out of 13

基於內部 awk 變數 NR 的預設 print $0 動作和條件:

# awk 'BEGIN {print "First 3 coins"} NR<4' coins.txt
First 3 coins                                                  
gold     1    1986  USA                 American Eagle         
gold     1    1908  Austria-Hungary     Franz Josef 100 Korona 
silver  10    1981  USA                 ingot

使用 C 風格的 printf 格式化:

# awk '{printf ("%s \t %3.2f\n", $1, $2)}' coins.txt
gold     1.00                                      
gold     1.00                                      
silver   10.00                                     
gold     1.00                                      
gold     1.00                                      
gold     0.50                                      
gold     0.10                                      
silver   1.00                                      
gold     0.25                                      
silver   0.50                                      
silver   1.00                                      
gold     0.25                                      
gold     1.00

條件例子

awk 'NR % 6'            # prints all lines except those divisible by 6
awk 'NR > 5'            # prints from line 6 onwards (like tail -n +6, or sed '1,5d')
awk '$2 == "foo"'       # prints lines where the second field is "foo"
awk '$2 ~ /re/'         # prints lines where the 2nd field mateches the regex /re/
awk 'NF >= 6'           # prints lines with 6 or more fields
awk '/foo/ && !/bar/'   # prints lines that match /foo/ but not /bar/
awk '/foo/ || /bar/'    # prints lines that match /foo/ or /bar/ (like grep -e 'foo' -e 'bar')
awk '/foo/,/bar/'       # prints from line matching /foo/ to line matching /bar/, inclusive
awk 'NF'                # prints only nonempty lines (or: removes empty lines, where NF==0)
awk 'NF--'              # removes last field and prints the line

通過新增動作 {...},可以列印特定欄位,而不是整行,例如:

awk '$2 ~ /re/{print $3 " " $4}'

列印第二個欄位匹配正規表示式/ re /的第三和第四個欄位。

一些字串函式

substr() 功能:

# awk '{print substr($3,3) " " substr($4,1,3)}' 
86 USA                                            
08 Aus                                            
81 USA                                            
84 Swi                                            
79 RSA                                            
81 RSA                                            
86 PRC                                            
86 USA                                            
86 USA                                            
86 USA                                            
87 USA                                            
87 USA                                            
88 Can                                            

match(s, r [, arr]) 返回正在發生正規表示式 rs 中的位置,並設定 RSTARTRLENGTH 的值。如果提供了引數 arr,則返回陣列 arr,其中元素被設定為匹配的帶括號的子表示式。arr 的第 0 個元素匹配設定為整個正規表示式匹配。表示式 arr[n, "start"]arr[n, "length"] 也提供每個匹配子字串的起始位置和長度。

更多字串函式:

sub(/regexp/, "newstring"[, target])
gsub(/regexp/, "newstring"[, target])
toupper("string")
tolower("string")

宣告

一個簡單的陳述通常是以下任何一種:

variable = expression 
print [ expression-list ] 
printf format [ , expression-list ] 
next # skip remaining patterns on this input line
exit # skip the rest of the input

如果 stat1stat2 是陳述,以下也是陳述:

{stat}

{stat1;  stat2}

{stat1 
stat2}

if ( conditional ) statement [ else statement ]

以下標準 C-like 是構造語句:

if ( conditional ) statement [ else statement ]
while ( conditional ) statement
for ( expression ; conditional ; expression ) statement
break    # usual C meaning 
continue # usual C meaning 

用於列印可變長度描述元素的 C 樣式迴圈,從欄位 4 開始:

# awk '{out=""; for(i=4;i<=NF;i++){out=out" "$i}; print out}' coins.txt
USA American Eagle                    
Austria-Hungary Franz Josef 100 Korona
USA ingot                             
Switzerland ingot                     
RSA Krugerrand                        
RSA Krugerrand                        
PRC Panda                             
USA Liberty dollar                    
USA Liberty 5-dollar piece            
USA Liberty 50-cent piece             
USA Constitution dollar               
USA Constitution 5-dollar piece       
Canada Maple Leaf

請注意,i 初始化為 0。

如果條件和計算應用於通用欄位:

# awk '/gold/ {if($3<1980) print $0 "$" 425*$2}' coins.txt    
gold     1    1908  Austria-Hungary     Franz Josef 100 Korona      $425
gold     1    1979  RSA                 Krugerrand                  $425   

AWK 可執行指令碼

#!/usr/bin/gawk -f
# This is a comment
(pattern) {action}
...

傳遞 shell 變數

# var="hello"
# awk -v x="$var" 'BEGIN {print x}'
hello