awk命令教程,awk命令用法举例

发布时间:2020-01-29编辑:脚本学堂
有关awk命令的使用教程,介绍了awk基础知识,awk命令的常用参数选项,awk命令格式化数据的实例教程,有需要的朋友参考下。

数据验证本质上是否定的:不是打印具备期望属性的行,而是打印可疑的行。如下程序使用对比模式 将5个数据合理性测试应用于 emp.data 的每一行::
 

NF != 3     { print $0, "number of fields is not equal to 3" }
$2 < 3.35   { print $0, "rate is below minimum wage" }
$2 > 10     { print $0, "rate exceeds $10 per hour" }
$3 < 0      { print $0, "negative hours worked" }
$3 > 60     { print $0, "too many hours worked" }
 

如果没有错误,则没有输出。

BEGIN与END

特殊模式 BEGIN 用于匹配第一个输入文件的第一行之前的位置, END 则用于匹配处理过的最后一个文件的最后一行之后的位置。这个程序使用 BEGIN 来输出一个标题::
 

BEGIN { print "Name    RATE    HOURS"; print ""}
      { print }
 

输出为::
 

NAME    RATE    HOURS

Beth    4.00    0
Dan     3.75    0
Kathy   4.00    10
Mark    5.00    20
Mary    5.50    22
Susie   4.25    18
 

程序的动作部分你可以在一行上放多个语句,不过要使用分号进行分隔。注意 普通的 print 是打印当前输入行,与之不同的是 print “” 会打印一个空行。

1.5 使用AWK进行计算

一个动作就是一个以新行或者分号分隔的语句序列。你已经见过一些其动作仅是单个 print 语句的例子。本节将提供一些执行简单的数值以及字符串计算的语句示例。在这些语句中,你不仅可以使用像 NF 这样的内置变量,还可以创建自己的变量用于计算、存储数据诸如此类的操作。awk中,用户创建的变量不需要声明。

计数
这个程序使用一个变量 emp 来统计工作超过15个小时的员工的数目::
 

$3 > 15 { emp = emp + 1 }
END     { print emp, "employees worked more than 15 hours" }
 

对于第三个字段超过15的每行, emp 的前一个值加1。以 emp.data 为输入,该程序产生::
3 employees worked more than 15 hours
用作数字的awk变量的默认初始值为0,所以我们不需要初始化 emp 。

求和与平均值

为计算员工的数目,我们可以使用内置变量 NR ,它保存着到目前位置读取的行数;在所有输入的结尾它的值就是所读的所有行数。
 

END { print NR, "employees" }
输出为::
6 employees
 

如下是一个使用 NR 来计算薪酬均值的程序::
 

{ pay = pay + $2 * $3 }
END { print NR, "employees"
      print "total pay is", pay
      print "average pay is", pay/NR
    }
 

第一个动作累计所有员工的总薪酬。 END 动作打印出
6 employees
total pay is 337.5
average pay is 56.25
很明显, printf 可用来产生更简洁的输出。并且该程序也有个潜在的错误:在某种不太可能发生的情况下, NR 等于0,那么程序会试图执行零除,从而产生错误信息。

处理文本

awk的优势之一是能像大多数语言处理数字一样方便地处理字符串。awk变量可以保存数字也可以保存字符串。
此程序会找出时薪最高的员工::
 

$2 > maxrate { maxrate = $2; maxemp = $1 }
END { print "highest hourly rate:", maxrate, "for", maxemp }
输出:
highest hourly rate: 5.50 for Mary

这个程序中,变量 maxrate 保存着一个数值,而变量 maxemp 则是保存着一个字符串。(如果有几个员工都有着相同的最大时薪,该程序则只找出第一个。)

字符串连接

可以合并老字符串来创建新字符串。这种操作称为 连接(concatenation) 。程序
 

 { names = names $1 " "}
END { print names }

通过将每个姓名和一个空格附加到变量 names 的前一个值, 来将所有员工的姓名收集进单个字符串中。最后 END 动作打印出 names 的值::
Beth Dan Kathy Mark Mary Susie
awk程序中,连接操作的表现形式是将字符串值一个接一个地写出来。对于每个输入行,程序的第一个语句先连接三个字符串: names 的前一个值、当前行的第一个字段以及一个空格,然后将得到的字符串赋值给 names 。因此,读取所有的输入行之后, names 就是个字符串,包含所有员工的姓名,每个姓名后面跟着一个空格。用于保存字符串的变量的默认初始值是空字符串(也就是说该字符串包含零个字符),因此这个程序中的 names 不需要显式初始化。

打印最后一个输入行

虽然在 END 动作中 NR 还保留着它的值,但 $0 没有。程序
 

   { last = $0 }
END { print last }
 

是打印最后一个输入行的一种方式::
Susie   4.25    18
内置函数

我们已看到awk提供了内置变量来保存某些频繁使用的数量,比如:字段的数量和输入行的数量。类似地,也有内置函数用来计算其他有用的数值。除了平方根、对数、随机数诸如此类的算术函数,也有操作文本的函数。其中之一是 length ,计算一个字符串中的字符数量。例如,这个程序会计算每个人的姓名的长度::
 

{ print $1, length($1) }
结果::

Beth 4
Dan 3
Kathy 5
Mark 4
Mary 4
Susie 5
 

行、单词以及字符的计数

这个程序使用了 length 、 NF 、以及 NR 来统计输入中行、单词以及字符的数量。为了简便,我们将每个字段看作一个单词。
  

  { nc = nc + length($0) + 1
      nw = nw + NF
    }
END { print NR, "lines,", nw, "words,", nc, "characters" }
文件 emp.data 有:
6 lines, 18 words, 77 characters
 

$0 并不包含每个输入行的末尾的换行符,所以我们要另外加个1。

1.6 控制语句

Awk为选择提供了一个 if-else 语句,以及为循环提供了几个语句,所以都效仿C语言中对应的控制语句。它们仅可以在动作中使用。
if-else语句

如下程序将计算时薪超过6美元的员工的总薪酬与平均薪酬。它使用一个 if 来防范计算平均薪酬时的零除问题。
 

$2 > 6 { n = n + 1; pay = pay + $2 * $3 }
END    { if (n > 0)
            print n, "employees, total pay is", pay,
                     "average pay is", pay/n
         else
             print "no employees are paid more than $6/hour"
        }
emp.data 的输出是::
no employees are paid more than $6/hour
 

if-else 语句中,if 后的条件会被计算。如果为真,执行第一个 print 语句。否则,执行第二个 print 语句。注意我们可以使用一个逗号将一个长语句截断为多行来书写。

while语句

一个 while 语句有一个条件和一个执行体。条件为真时执行体中的语句会被重复执行。这个程序使用公式 value=amount(1+rate)years

来演示以特定的利率投资一定量的钱,其数值是如何随着年数增长的。
 

# interest1 - 计算复利
#   输入: 钱数    利率    年数
#   输出: 复利值

{   i = 1
    while (i <= $3) {
        printf("t%.2fn", $1 * (1 + $2) ^ i)
        i = i + 1
    }
}
 

条件是 while 后括弧包围的表达式;循环体是条件后大括号包围的两个表达式。 printf 规格字符串中的 t 代表制表符; ^ 是指数操作符。从 # 开始到行尾的文本是注释,会被awk忽略,但能帮助程序的读者理解程序做的事情。

可以为这程序输入三个一组的数字,看看不一样的钱数、利率、以及年数会产生什么。例如,如下事务演示了1000美元,利率为6%与12%,5年的复利分别是如何增长的::
 

$ awk -f interest1
1000 .06 5
        1060.00
        1123.60
        1191.02
        1262.48
        1338.23
1000 .12 5
        1120.00
        1254.40
        1404.93
        1573.52
        1762.34
 

for语句
另一个语句, for ,将大多数循环都包含的初始化、测试、以及自增压缩成一行。如下是之前利息计算的 for 版本::
 

# interest1 - 计算复利
#   输入: 钱数    利率    年数
#   输出: 每年末的复利
{ for (i = 1; i <= $3; i = i + 1)
    printf("t%.2fn", $1 * (1 + $2) ^ i)
}
 

初始化 i = 1 只执行一次。接下来,测试条件 i <= $3 ;如果为真,则执行循环体的 printf 语句。循环体执行结束后执行自增 i = i + 1 ,接着由另一次条件测试开始下一个循环迭代。代码更加紧凑,并且由于循环体仅是一条语句,所以不需要大括号来包围它。

1.7 数组
awk为存储一组相关的值提供了数组。虽然数组给予了awk很强的能力,但在这里我们仅展示一个简单的例子。如下程序将按行逆序打印输入。第一个动作将输入行存为数组 line 的连续元素;即第一行放在 line[1] ,第二行放在 line[2] , 依次继续。 END 动作使用一个 while 语句从后往前打印数组中的输入行::
 

# 反转 - 按行逆序打印输入
    { line[NR] = $0 }  # 记下每个输入行
END { i = NR           # 逆序打印
      while (i > 0) {
        print line[i]
        i = i - 1
      }
    }
 

以 emp.data 为输入,输出为
 

Susie    4.25   18
Mary     5.50   22
Mark     5.00   20
Kathy    4.00   10
Dan      3.75   0
Beth     4.00   0
 

如下是使用 for 语句实现的相同示例::
 

# 反转 - 按行逆序打印输入
{ line[NR] = $0 }   # 记下每个输入行
END { for (i = NR; i > 0; i = i - 1)
        print line[i]
    }