本文探讨了 awk 的功能,现在您已经知道如何将命令构建为可执行脚本,因此这些功能更容易使用。
逻辑运算符和条件
您可以使用逻辑运算符 **and** (写作 **&&**) 和 **or** (写作 **||**) 来增加条件的具体性。
例如,要选择并仅打印第二列中包含字符串“purple”*并且*第三列中的金额小于五的记录
$2 == "purple" && $3 < 5 {print $1}
如果一条记录在第二列中包含“purple”,但在第三列中的值大于或等于 5,则*不*会被选中。同样,如果一条记录满足第三列的要求,但在第二列中缺少“purple”,则也*不*会被选中。
下一个命令
假设您想要选择文件中金额大于或等于 8 的每个记录,并打印一个带有两个星号 ( ** ) 的匹配记录。您还想用一个星号 ( * ) 标记介于 5(含)和 8 之间的每个记录。有几种方法可以做到这一点,其中一种方法是使用 **next** 命令指示 awk 在执行操作后停止扫描并继续处理*下一个*记录。
这是一个例子
NR == 1 {
print $0;
next;
}
$3 >= 8 {
printf "%s\t%s\n", $0, "**";
next;
}
$3 >= 5 {
printf "%s\t%s\n", $0, "*";
next;
}
$3 < 5 {
print $0;
}
BEGIN 命令
**BEGIN** 命令允许您在 awk 开始扫描文本文件之前打印和设置变量。 例如,您可以通过在 **BEGIN** 语句中定义输入和输出字段分隔符,在 awk 脚本中设置它们。 此示例改编了上一篇文章中的简单脚本,以用于字段由逗号而不是空格分隔的文件
#!/usr/bin/awk -f
#
# Print each record EXCEPT
# IF the first record contains "raspberry",
# THEN replace "red" with "pi"
BEGIN {
FS=",";
}
$1 == "raspberry" {
gsub(/red/,"pi")
}
END 命令
与 **BEGIN** 类似,**END** 命令允许您在 awk 完成对您正在处理的文本文件的扫描后执行操作。 如果您想打印所有记录中某个值的累积结果,您只能在扫描和处理完所有记录后执行此操作。
**BEGIN** 和 **END** 命令每个只运行一次。 它们之间的所有规则在*每个记录*上运行零次或多次。 换句话说,您的大部分 awk 脚本是一个循环,它在您正在处理的文本文件的每一行中执行,**BEGIN** 和 **END** 规则除外,它们在循环之前和之后运行。
这是一个如果没有 **END** 命令就不可能实现的示例。 此脚本接受 Unix 命令 **df** 的输出值,并为每个新记录递增两个自定义变量(**used** 和 **available**)。
$1 != "tempfs" {
used += $3;
available += $4;
}
END {
printf "%d GiB used\n%d GiB available\n", used/2^20, available/2^20;
}
将脚本保存为 **total.awk** 并尝试一下
df -l | awk -f total.awk
**used** 和 **available** 变量的行为类似于许多其他编程语言中的变量。 您可以随意创建它们,无需声明它们的类型,并且可以随意向它们添加值。 在循环结束时,脚本将相应列中的记录加在一起并打印总计。
数学
从目前为止的所有逻辑运算符和临时计算中您可能已经知道,awk 进行数学运算非常自然。 可以说,这使其成为您终端中非常有用的计算器。 您可以简单地使用 awk 及其特殊的 **BEGIN** 函数来避免需要文件参数,而不是努力记住 **bc** 相当不寻常的语法
$ awk 'BEGIN { print 2*21 }'
42
$ awk 'BEGIN {print 8*log(4) }'
11.0904
诚然,对于简单(和不太简单)的数学运算来说,这仍然需要大量打字,但是编写一个前端并不需要花费太多精力,这是一个供您探索的练习。
本文改编自 Hacker Public Radio(一个社区技术播客)的一集。
2 条评论