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