注:第二版的第2章是全新的。
第一版的第2章,是对Awk语言的详细说明。作者考虑到里面又长又干,不符合现代读者的习惯,于是在第二版中,将原第2章全部挪到 附录A(参考手册) 里面。
第一版的附录A是Awk语言总结,是参考手册的简化版,在第二版废弃。
第一版的附录B是练习答案,也在第二版去掉,改成放到网上。
Awk非常适用于制作小工具或者个人使用的脚本,它们可以帮你完成重复性的工作,或者处理一些(别人不关心但只有你在乎的)特别古怪的计算。
本章我们会看到这样一些样例,这些特定的程序不一定刚好适合你(运气好的话能碰到几个),但它们也许能启发你写出一些自己的程序,或者能给出一些编程技巧供你使用。
本章围绕着如下内容来组织:简单计算,基本的选择、转换和汇总操作,这些都是Awk最初的设计意图。每个例子除了本身是有趣或有用的,还能展示一些Awk语言本身的特性,并说明一些有用的编程技巧。一些例子不仅仅涉及Awk,还包含一些其他的标准Unix工具,以及对Unix环境的高效利用。
Awk是个不错的可编程计算器,你可以用它的计算封装成命令,并加入到你的个人工具箱。本节给出了我们觉得有用的几个小程序。
体重指数BMI是一个广泛使用的身体脂肪度量指标,公式为 bmi = weight / height 2。
“正常”的BMI范围在18到25之间,25到30为“超重”,30以上为“肥胖”。官方的定义使用了米和千克做单位,但下面的例子用的是英寸和磅,所以必须转换下:1千克=2.2磅,1英寸=2.54厘米。
# bmi计算
awk 'BEGIN { print "enter pounds inches" }
{ printf("%.1f\n", ($1/2.2) / ($2 * 2.54/100) ^ 2) } '
把上面的内容存到一个可执行文件中并命名为 bmi,就能把它当作程序来运行了。作者运行的效果是:
$ bmi
enter pounds inches
190 74
24.4
所以作者“差不多”正常。
运行敏感性测试(?)也很方便,比如评估节食效果或测量错误:
$ bmi
enter pounds inches
195 74
25.1
200 75
25.1
上面BMI样例中的转换系数正确吗?如果不记得了,可以使用Unix程序 units ,它给出了几百种单位转换系数:
$ units
586 units, 56 prefixes
You have: inches
You want: meters
* 0.0254
/ 39.370079
You have: pounds
You want: kg
* 0.45359237
/ 2.2046226
下面我们自己写一个类似功能的 cf 程序来做常用的度量单位转换,但用起来更方便:我们不问用户想做什么操作,只要用户在命令行参数提供一个数值,cf 就把所有单位的双向转换系数都打印出来。cf 程序最初是作为一个 华氏-摄氏(Celsius to Fahrenheit)温度转换工具,这也是 cf 名字的由来。例如,外面的温度是 7℃,对应多少华氏度?
$ cf 7
7 C = 44.6 F; 7 F = -13.9 C
随着时间推移,加入了更多的转换,比如长度和重量。74英寸是多少厘米?74千克是多少磅?
$ cf 74
74 C = 165.2 F; 74 F = 23.3 C
74 cm = 29.1 in; 74 in = 188.0 cm
74 kg = 162.8 lb; 74 lb = 33.6 kg
cf 程序会把所有都打出来,用户自己选择想看的。
下面是 cf 程序的源代码。里面使用了内置数组 ARGV 来获取所需的命令行参数。所有代码都写在BEGIN 块里面,不会去读任何文件。
# cf: 温度、长度、重量 单位转换
awk 'BEGIN {
t = ARGV[1] # 首个命令行参数
printf("%s C = %.1f F; %s F = %.1f C\n",
t, t*9/5 + 32, t, (t-32)*5/9)
printf("%s cm = %.1f in; %s in = %.1f cm\n",
t, t/2.54, t, t*2.54)
printf("%s kg = %.1f lb; %s lb = %.1f kg\n",
t, 2.2*t, t, t/2.2)
}' $*
脚本里面的 $* 是 shell的表示法,用来表示程序接收到的所有参数,shell会将其展开为字符串列表传给程序。大部分情况下传给awk的参数是文件名,不过在 cf 这里,第一个参数是要转换的数字,其他参数被忽略。
Awk将程序被调用时的参数储存在数组 ARGV 中,ARGV[1]是第一个参数,ARGV[2]是第二个,以此类推直到 ARGV[ARGC - 1]。ARGC 是所有参数的数量,ARGV[0]是程序名,通常是awk。在后面的例子里会有更多ARGV的信息,也可以参考附录 A.5.5。
上面的 bmi 和 cf 程序叫做“shell脚本”:用脚本语言写程序,并保存在可执行文件中,这样它们就能和用编译型语言(如C语言)编写并编译后得到的可执行程序一样的方式,被操作系统执行了。要让一个文件在Unix系统中可执行,需要使用 chmod (change mode)命令
$ chmod +x bmi cf
如果该脚本放在你的shell搜索路径中(通常是 $HOME/bin),你就能像使用内置命令一样使用它们,前面的例子就是如此。