温馨提示,本文适合有一定编程基础的人阅读。
在学习本文之前,相信有一部分人和我之前一样,对awk
的认知停留于对某个简单命令的使用。对于我们做 java 开发的,最经典的一个案例莫过于重启服务时经常看到的一个脚本
#!/bin/bash # 重启xx服务 ps -ef | grep application | grep -v grep | awk '{print $2}' | xargs kill -9 # 重启服务 nohup java -jar xxx.jar ...
在上面的一个脚本中我们使用了awk
命令,也可以看懂这个命令的作用,至于到底是什么原理或者说为什么有这样的效果很多人是不清楚。反正大家都是这么写的,我要做的只是 copy copy 改~。那么今天开始我们将一起学习awk
,其实awk
远比你认知的要更为强大!
例如有以下一个文件 employ.dat,文件包含员工姓名、每小时的工资、工作时长,每一行代表一个员工的记录
张三 25.00 0 李四 22.75 0 王五 19.00 10 赵六 30.00 20 钱七 42.50 22 王八 80.00 18
现在想要打印每个员工的姓名以及工资(时薪 * 工作时长),而且雇员的工作时长(第三列)必须大于0,这时候只需要下面的一行命令即可以完成上面的工作:
awk '$3 > 0 {print $1 ,$2 * $3}' employ.dat
执行上面的命令后结果如下:
王五 190 赵六 600 钱七 935 王八 1440
通过输出的结果可以看出上面的命令已经很好的完成了我们的需求。
该行命令告诉操作系统运行 awk 程序, 被运行的程序用单引号包围起来, 从输入文件 emp.data 获取数据。单引号包围的部分是一个完整的 awk 程序. 它由一个单独的 模式–动作 语句 (pattern-action statement) 组成. 模式 $3 > 0 扫描每一个输入行, 如果该行的第三列 (或者说 字段 (field)) 大于零, 则动作
{print $1 ,$2 * $3}
再来一个需求,打印出工作时长为0的员工姓名,相信有了上面的例子,完成这个需求也很简单:
awk '$3 == 0 {print $1}' employ.dat
在上面的命令行中, 被单引号包围的部分是使用 awk 语言编写的程序,每一个 awk 程序都是由一个或多个 模式–动作 语句组成的序列:
pattern { action } pattern { action } ...
awk 的基本操作是在由输入行组成的序列中, 陆续地扫描每一行, 搜索可以被模式 匹配 (match) 的行.。“匹配”的精确含义依赖于问题中的模式, 比如, 对于 $3 > 0, 意味着 “条件为真”.。每一个输入行轮流被每一个模式测试. 每匹配一个模式, 对应的动作 (可能包含多个步骤) 就会执行。 然后下一行被读取, 匹配重新开始. 这个过程会一起持续到所有的输入被读取完毕为止。
运行一个 awk 程序有多种方式. 可以键入下面这种形式的命令
awk 'program' input files
这个命令对指定的输入文件的每一行, 执行 program. 例如你可以键入
awk '$3 == 0 { print $1 }' file1 file2
如果一个动作没有模式, 对于每一个输入行, 该动作都会被执行. 语句 print 会打印每一个当前输入行,
所以程序
{ print }
会将它所有的输入打印到标准输出. 因为 $0
表示一整行, 所以程序
{ print $0 }
完成同样的工作
这种方式前面我们已经使用到了,例如打印第一列和第三列可以使用
{print $1, $3}
Awk 计算当前输入行的字段数量, 并将它存储在
一个内建的变量中, 这个变量叫作 NF (Number Of Field)。因此程序
{ print NF, $1, $NF }
将会打印每一个输入行的字段数量, 第一个字段, 以及最后一个字段。
Awk 提供了另一个内建变量 NR (Number Of Record), 这个变量计算到目前为止, 读取到的行的数量. 我们可以使用 NR 和 $0为 employ.dat 的每一行加上行号:
awk '{ print NR, $0 }' employ.dat
输出就像这样:
1 张三 25.00 0 2 李四 22.75 0 3 王五 19.00 10 4 赵六 30.00 20 5 钱七 42.50 22 6 王八 80.00 18
可以把单词放在字段与算术表达式之间:
awk '{ print "第",NR, "行记录是", $0 }' employ.dat
第 1 行记录是 张三 25.00 0 第 2 行记录是 李四 22.75 0 第 3 行记录是 王五 19.00 10 第 4 行记录是 赵六 30.00 20 第 5 行记录是 钱七 42.50 22 第 6 行记录是 王八 80.00 18
print
用于简单快速的输出. 如果读者想要格式化输出, 那么就需要使用 printf 语句。
printf
语句具有形式
printf(format, value1, value2, ... , valuen)
format 是一个字符串, 它包含按字面打印的文本, 中间散布着格式说明符, 格式说明符用于说明如何打印值。一个格式说明符是一个 %, 后面跟着几个字符, 这些字符控制一个 value 的输出格式. 第一个格式说明符说明value1 的输出格式, 第二个格式说明符说明 value2 的输出格式, 依次类推. 于是, 格式说明符的数量应该和被打印的 value 一样多。
这个程序使用 printf 打印每位员工的工资:
awk '{ printf(" %s 的工资是 %.2f元\n", $1, $2 * $3) }' employ.dat
张三 的工资是 0.00元 李四 的工资是 0.00元 王五 的工资是 190.00元 赵六 的工资是 600.00元 钱七 的工资是 935.00元 王八 的工资是 1440.00元
特殊的模式 BEGIN 在第一个输入文件的第一行之前被匹配, END 在最后一个输入文件的最后一行被处理
之后匹配. 这个程序使用 BEGIN 打印一个标题:
awk 'BEGIN { print "姓名 时薪 工作时长"; print "" } { print }' employ.dat
姓名 时薪 工作时长 张三 25.00 0 李四 22.75 0 王五 19.00 10 赵六 30.00 20 钱七 42.50 22 王八 80.00 18
今天的内容就到这里了,欲知后事如何,请听下回分解。