编写一个大型 Awk 程序

前面的示例虽然有趣,但它们只是对 coins.txt 文件进行了零散的分析。为什么不让 Awk 一次性 计算所有有趣的信息呢?

如何编写一个完整的 Awk 脚本

直接在命令行输入大量 Awk 语句是不现实的,但这个问题很容易解决——我们可以把 Awk 命令写入一个文件,然后让 Awk 执行这个文件

执行 Awk 脚本的基本格式如下:

awk -f awk脚本文件名 数据文件名

例如:

awk -f summary.awk coins.txt

这样,我们可以编写更复杂的 Awk 程序,而不受命令行输入长度的限制。


“完整”金币数据分析程序

假设我们想让 Awk 生成如下统计信息:

Summary Data for Coin Collection:

    Gold pieces:                   nn
    Weight of gold pieces:         nn.nn
    Value of gold pieces:        nnnn.nn

    Silver pieces:                 nn 
    Weight of silver pieces:       nn.nn
    Value of silver pieces:      nnnn.nn

    Total number of pieces:        nn  
    Value of collection:         nnnn.nn

下面是实现该功能的 Awk 脚本:

# 这是一个用于统计金币和银币信息的 Awk 脚本
/gold/    { num_gold++; wt_gold += $2 }                         # 统计金质硬币数量和重量
/silver/  { num_silver++; wt_silver += $2 }                     # 统计银质硬币数量和重量

END {
    val_gold = 485 * wt_gold;                                    # 计算金币总价值
    val_silver = 16 * wt_silver;                                # 计算银币总价值
    total = val_gold + val_silver;

    print "Summary data for coin collection:";
    printf("\n");
    printf("    Gold pieces:\t\t%4i\n", num_gold);
    printf("    Weight of gold pieces:\t%7.2f\n", wt_gold);
    printf("    Value of gold pieces:\t%7.2f\n", val_gold);
    printf("\n");
    printf("    Silver pieces:\t\t%4i\n", num_silver);
    printf("    Weight of silver pieces:\t%7.2f\n", wt_silver);
    printf("    Value of silver pieces:\t%7.2f\n", val_silver);
    printf("\n");
    printf("    Total number of pieces:\t%4i\n", NR);
    printf("    Value of collection:\t%7.2f\n", total);
}

程序解析

1. 注释

在 Awk 中,# 用于注释,# 之后的所有内容都会被忽略。

2. 变量 num_goldnum_silver

/gold/    { num_gold++; wt_gold += $2 }
/silver/  { num_silver++; wt_silver += $2 }
  • num_gold++ 统计金质硬币的数量,num_silver++ 统计银质硬币的数量。
  • wt_gold += $2 累加金质硬币的总重量,wt_silver += $2 统计银质硬币的总重量。

3. END 代码块

END {
    val_gold = 485 * wt_gold;
    val_silver = 16 * wt_silver;
    total = val_gold + val_silver;
}
  • 计算金币价值:假设金价 $485/盎司,所以 val_gold = 485 * wt_gold
  • 计算银币价值:假设银价 $16/盎司,所以 val_silver = 16 * wt_silver
  • 计算总价值total = val_gold + val_silver

4. printf 格式化输出

printf("    Gold pieces:\t\t%4i\n", num_gold);
printf("    Weight of gold pieces:\t%7.2f\n", wt_gold);
  • %4i:表示输出整数(num_gold),占 4 个字符宽度,右对齐。
  • %7.2f:表示输出浮点数wt_gold),共 7 个字符宽度,小数部分保留 2 位

运行脚本

将上面的 Awk 代码保存到 summary.awk 文件中,然后运行:

awk -f summary.awk coins.txt

运行结果

Summary data for coin collection:

    Gold pieces:		   9
    Weight of gold pieces:	   6.10
    Value of gold pieces:	2958.50

    Silver pieces:		   4
    Weight of silver pieces:	  12.50
    Value of silver pieces:	 200.00

    Total number of pieces:	  13
    Value of collection:	3158.50

关于 printf 语句

1. printf 语法

printf("<格式化代码>", <参数>)

2. 常见特殊字符

字符 功能
\n 换行
\t 制表符(对齐)

3. 常见格式化代码

代码 含义
%i%d 整数
%f 浮点数
%s 字符串

4. 示例

printf("%2d", 7)       # 输出: " 7"(宽度为 2,右对齐)
printf("%7.2f", 123.456)  # 输出: "  123.46"(保留 2 位小数,总宽度 7)

注意:

  • printf 不会自动换行,所以需要手动添加 \n
  • \t 用于创建 对齐格式,默认 每 8 个字符 作为一个对齐点。

练习

  1. 修改 summary.awk 统计并显示 coins.txt 中的不同国家的数量。
  2. 编写 Awk 脚本,统计空行和非空行的数量(使用 NF 变量)。
  3. 修改练习 2,计算每行的平均单词数。

在下一章,我们将学习如何编写多行 Awk 代码,以便实现更加复杂的功能。

最后修改: 2025年01月30日 星期四 00:35