6.0 高级脚本结构
虽然模式-动作规则是 AWK 的基础,但它的实用性远不止于此,它还通过一系列高级结构实现了真正的脚本编写。这些特性——内置变量、控制流、数组和函数——的战略意义在于,它们将 AWK 从一个简单的过滤器提升为一个完整的编程环境,能够管理状态、实现复杂的逻辑并构建可重用的模块化代码。
6.1 使用内置变量管理状态
AWK 提供了一套丰富的内置变量,这些变量由运行时环境自动管理。这些变量是至关重要的工具,它们为脚本提供了关于输入数据的上下文信息,例如当前行号 (NR) 或该行上的字段数 (NF)。此外,它们还允许通过修改字段分隔符 (FS) 和输出字段分隔符 (OFS) 等变量,对数据的处理和格式化方式进行精细控制。
内置变量分为两类:所有 AWK 版本中可用的标准变量和 GNU AWK (GAWK) 中发现的特定扩展。
表1:标准内置变量
| 请按需咨询 | 描述 |
| 农业研究中心 | 命令行参数的数量。 |
| 无人驾驶汽车 | 包含命令行参数的数组。 |
| 文件名 | 当前输入文件的名称。 |
| FS | 输入字段分隔符(默认为空格)。例如:awk 'BEGIN {print “FS = ” FS}' |
| NF | 当前输入记录中的字段数。例如:echo “One Two Three” | awk 'NF > 2' |
| NR | 到目前为止已处理的输入记录总数。例如:echo “One\nTwo\nThree” | awk 'NR < 3' |
| 飞行服务队 | 输出字段分隔符(默认为空格)。 |
| ORS | 输出记录分隔符(默认为换行符)。 |
| RS | 输入记录分隔符(默认为换行符)。 |
| $0 | 当前输入记录的全部内容。 |
| $n | 当前记录中的第 n 个字段(例如,$1、$2)。 |
表 2:GNU AWK (GAWK) 特定变量
| 请按需咨询 | 描述 |
| 阿尔金 | 当前正在处理的文件在 ARGV 中的索引。 |
| 错误号 | 如果重定向或 close() 失败,则会显示一个描述错误的字符串。 |
| 忽略案例 | 如果设置为非零值,则启用不区分大小写的模式匹配。 |
| 信息 | 包含有关正在运行的进程的信息(例如,其进程 ID)的关联数组。 |
6.2 利用控制流和循环构建逻辑
除了简单的模式-动作规则之外,AWK 还集成了标准的编程控制结构,从而能够开发复杂的逻辑。这些结构允许脚本做出决策、有条件地执行代码以及重复执行操作,使 AWK 成为一个更完善的编程环境。
条件陈述
- if 声明: 如果条件为真,则执行操作。
- 语法: 如果(条件)操作
- 计费示例: awk 'BEGIN {num = 10; if (num % 2 == 0) printf “%d 是偶数。\n”, num }'
- 如果别的 声明: 如果条件为真,则执行一个操作;如果条件为假,则执行另一个操作。
- 语法: 如果(条件)执行操作1,否则执行操作2
- 计费示例: awk 'BEGIN { num = 11; if (num % 2 == 0) printf “%d 是偶数。\n”, num; else printf “%d 是奇数。\n”, num }'
- 如果-否则-如果 梯子: 将多个条件串联起来以处理各种情况。
- 计费示例: awk 'BEGIN { a = 30; if (a==10) print “a = 10”; else if (a == 20) print “a = 20”; else if (a == 30) print “a = 30”; }'
循环构造
- HPMC胶囊 循环: 重复执行某个动作特定次数。
- 语法: 用于(初始化;条件;递增/递减)操作
- 计费示例: awk 'BEGIN { for (i = 1; i <= 5; ++i) print i }'
- 而 循环: 只要条件成立,就重复执行某个动作。
- 语法: 当(条件)动作
- 计费示例: awk 'BEGIN {i = 1; while (i < 6) { print i; ++i } }'
- 在做 循环: 与 while 循环类似,但条件是在最后检查的,保证操作至少执行一次。
- 语法: 当满足(条件)时执行操作
- 计费示例: awk 'BEGIN {i = 1; do { print i; ++i } while (i < 6) }'
循环控制和脚本终止
- break:立即终止最内层循环。
- 计费示例: awk 'BEGIN { sum = 0; for (i = 0; i < 20; ++i) { sum += i; if (sum > 50) break; } }'
- continue:跳过当前循环迭代的剩余部分,并继续进行下一次迭代。
- 计费示例: awk 'BEGIN { for (i = 1; i <= 20; ++i) { if (i % 2 == 0) print i ; else continue } }'
- exit:终止整个 AWK 脚本,可以选择返回状态码。
- 计费示例: awk 'BEGIN { sum = 0; for (i = 0; i < 20; ++i) { sum += i; if (sum > 50) exit(10); } }'
6.3 使用关联数组进行数据聚合
AWK 包含一种强大的数据结构,称为关联数组。与使用顺序整数作为索引的传统数组不同,AWK 的数组可以使用字符串。正是这一特性使 AWK 从简单的行处理器跃升为强大的数据聚合引擎,使其能够与更冗长的脚本语言在诸如统计词频、按 IP 地址汇总日志或按类别分组数据等任务上相媲美。
创建数组元素的语法很简单,就是赋值:array_name[index] = value
以下示例创建一个名为 fruits 的数组,其中键是水果名称,值是它们的颜色。
[jerry]$ awk 'BEGIN {
fruits[“mango”] = “yellow;
水果[“橙色”] =“橙色”;
print fruits[“orange”]“\n” fruits[“mango”];
}'
输出:
橙
黄色
要从数组中删除元素,可以使用 delete 语句:
[jerry]$ awk 'BEGIN {
fruits[“mango”] = “yellow;
水果[“橙色”] =“橙色”;
删除 fruits[“橙子”];
打印水果[“橙子”];
}'
由于在打印语句之前删除了“橙色”元素,因此该命令不会产生任何输出。
虽然 AWK 只支持一维数组,但可以通过将索引连接成一个字符串来模拟多维数组。例如,要模拟 array[0][0],可以使用类似 array[“0,0”] 的字符串索引。
6.4 使用函数创建模块化代码
AWK 支持内置函数和用户自定义函数,提供了一种创建可重用模块化脚本的机制。这对于管理大型程序的复杂性以及编写更易于阅读、测试和维护的代码至关重要。AWK 提供了大量内置函数,这些函数按算术运算、字符串运算、时间运算和位操作等类别进行分类。
对于自定义逻辑,用户可以定义自己的函数。
- 一般语法: 函数 function_name(参数) { 主体 }
以下示例存储在名为 functions.awk 的文件中,定义了用于查找两个数字的最小值和最大值的函数,并从 BEGIN 块中执行的主函数调用它们。
文件:functions.awk
# 返回最小值
函数 find_min(num1, num2){
如果 (num1 < num2) 返回 num1
返回 num2
}
# 返回最大值
函数 find_max(num1, num2){
如果 (num1 > num2) 返回 num1
返回 num2
}
# 主功能
function main(num1, num2){
# 找到最小值
result = find_min(10, 20)
打印“最小值 =”,结果
# 找出最大值
result = find_max(10, 20)
打印“最大值 =”,结果
}
# 脚本执行从这里开始
开始 {
main(10, 20)
}
执行此脚本后,会生成:
最低值 = 10
最大值 = 20
数据处理的核心逻辑一旦到位,最后一步就是管理结果的呈现和交付方式。