Awk - 一门有用的小语言
awk 是一种小型但功能强大的编程语言,用于处理文本。它由贝尔实验室的 Aho、Weinberger 和 Kerninghan 开发。
Julia Evans为 做了精彩的介绍awk
:
awk 将输入文件扫描为一系列行,并将每行拆分为多个字段。字段分隔符通常为空格,但您可以将其自定义为任何字符。
程序awk
是一系列“模式-动作”对,也就是说,程序会检查每一行是否与模式匹配,如果匹配,则执行该行对应的动作。Awk 可以交互使用,也可以运行已保存的程序。
以下是用类似 Python 的伪代码编写的 Awk 的功能:
initialize() # Initializes variables in BEGIN block
for line in input_lines: # Awk divides file / input into a list of lines
for condition, action in conditions: # A program is a list of condition-action pairs
if condition(line): #match line against condition
action() #perform action on match
以下是 Awk 的一些小片段:
1.你好,世界!
您可以awk
内联或通过文件运行程序:
awk 'BEGIN{ print "Hello, World!"}'
或者,您可以将其保存到文件中hello.awk
:
BEGIN{ print "Hello, World!"}
然后运行它awk -f hello.awk
2. 读取 CSV 并打印特定列
现在让我们做点有用的事!下载这个csv 文件,它是 2010 年洛杉矶市按邮政编码划分的人口普查数据。
从 csv 中读取前 3 行:head -3 2010_Census_Populations_by_Zip_Code.csv
Zip Code,Total Population,Median Age,Total Males,Total Females,Total Households,Average Household Size
91371,1,73.5,0,1,1,1
90001,57110,26.6,28468,28642,12971,4.4
我们将使用以下方法打印总计列awk -F, '{print $2}' 2010_Census_Populations_by_Zip_Code.csv
将-F,
字段分隔符设置为逗号,因为我们需要用逗号分隔才能获取 CSV 文件中的字段。$n
允许您使用第 n 列中的值。
3. 计算一些统计数据
awk 允许使用变量和函数。让我们通过计算整个城市的总人口来了解如何使用它们。
# total.awk
{s += $2}
END {print "Total population:", s}
变量默认初始化为 0。在这里,我们使用一个变量s
来保存总数。
运行此脚本awk -F, -f total.awk 2010_Census_Populations_by_Zip_Code.csv
,我们得到输出:Total population: 10603988
特殊变量和内置函数
awk 使用一些特殊的变量和函数来使你的程序更加紧凑:
- NF:一行中的字段数
- NR:行号
- $0:整个输入行
- length:给出字符串中的字符数
现在,我们将计算平均家庭规模,即总人口数除以家庭总数。我们感兴趣的列是 $2 和 $6。
我们还想计算每个邮政编码的平均人口数。我们的脚本:
# stats.awk
{ s += $2; h += $6;}
END {print "Total population:", s, "\nTotal households:", h, "\nAverage household size:", s/h, "\nAverage population per zip code:", s/NR}
NR
给出了总行数。但我们不需要标题行。我们可以使用tail
命令跳过第一行tail -n +2
。运行tail -n +2 2010_Census_Populations_by_Zip_Code.csv | awk -F, -f total.awk
结果如下:
Total population: 10603988
Total households: 3497698
Average household size: 3.0317
Average population per zip code: 33241.3
4.模式匹配
到目前为止,我们已经用 awk 做了一些有用的事情,但我们忽略了它最大的优势——模式匹配。我们可以基于字段值、正则表达式和行号进行匹配。
- 每隔一行打印一次:
NR%2 == 0 {print $0}
。此处 $0 代表整行。 - 打印人口 > 100,000 的所有邮政编码:
$2 > 100000 {print $1}
- 打印所有人口 > 10,000 且平均家庭规模 > 4 的邮政编码: 。我们可以使用and
$2 > 10000 && $7 > 4 { print $1}
组合条件, and 分别代表逻辑与和或。&&
||
进一步阅读
Awk 还有很多其他功能。以下是一些参考资料:
-
学习 Awk 的最佳资源是同一三人编写的《AWK 编程语言》。这本书超越了典型的编程语言教程,教你如何使用 Awk 的超能力构建多功能系统,例如关系数据库、解析器、解释器等。
-
《GNU Awk 有效 Awk 编程手册》是一本详尽的参考书。