awk 是一种强大的文本处理工具,主要用于在 Unix-like 系统(包括 Linux 和 macOS)中处理和分析结构化数据。它是基于模式匹配和动作的脚本语言,由 Alfred Aho、Peter Weinberger 和 Brian Kernighan 在 1977 年开发(故名"awk"取自三人姓氏首字母)。awk 常用于处理日志文件、CSV 数据、报表生成等场景。它支持正则表达式、变量、函数和数组,类似于一个小型编程语言。
awk 的核心思想是:读取输入文件(或标准输入),逐行处理,每行被拆分成字段(默认以空格分隔),然后根据模式执行动作。
1. 基本语法
awk 的基本命令格式:
awk [选项] '模式 {动作}' 文件名
- 模式:可选,用于匹配行(如正则表达式、条件判断)。如果省略,则对所有行执行动作。
- 动作:用大括号 {} 包围的语句,如 print、printf 等。如果省略,则默认打印匹配行。
- 文件名:输入文件,可以是多个文件或标准输入(用 - 表示)。如果省略,默认从标准输入读取。
示例:
awk '{print $1}' file.txt # 打印 file.txt 中每行的第一个字段
awk 脚本也可以写成独立文件:
awk -f script.awk file.txt
其中 script.awk 包含模式和动作。
2. 常用选项
awk 支持多种选项,以下是常见选项的表格:
| 选项 | 描述 | 示例 |
|---|---|---|
| -F fs | 指定字段分隔符(默认空格或制表符)。fs 可以是正则表达式。 | awk -F ":" '{print $1}' /etc/passwd (用冒号分隔,打印用户名) |
| -f file | 从文件中读取 awk 脚本。 | awk -f myscript.awk data.txt |
| -v var=value | 定义变量并赋值,可在 BEGIN 块中使用。 | awk -v name="Alice" 'BEGIN {print name}' |
| -W option | 特定实现选项(如 gawk 的 -W traditional 用于兼容模式)。 | awk -W version (显示版本) |
| -- | 结束选项处理,后续参数视为文件名。 | 用于处理以 - 开头的文件名。 |
注意:awk 有多种实现,如 nawk(New awk)、gawk(GNU awk,是 Linux 默认的)。gawk 扩展了标准 awk,支持更多功能。
3. 内置变量
awk 提供了许多内置变量,用于访问行、字段和环境信息。以下是常用内置变量的表格:
| 变量 | 描述 | 示例 |
|---|---|---|
| $0 | 当前整行内容。 | print $0 打印整行。 |
| $n | 第 n 个字段($1 是第一个)。 | print 1, 3 打印第一和第三个字段。 |
| NF | 当前行字段数。 | if (NF > 3) print $0 只打印字段数 >3 的行。 |
| NR | 当前记录号(行号,从 1 开始)。 | print NR, $0 带行号打印。 |
| FNR | 当前文件记录号(多文件时独立计数)。 | 与 NR 类似,但每个文件重置。 |
| FS | 字段分隔符(默认空格)。 | FS = "," 设置为逗号(CSV)。 |
| OFS | 输出字段分隔符(默认空格)。 | OFS = "\t" 输出用制表符分隔。 |
| RS | 记录分隔符(默认换行符)。 | RS = "" 以空行分隔段落。 |
| ORS | 输出记录分隔符(默认换行符)。 | ORS = "\n\n" 输出加空行。 |
| FILENAME | 当前文件名。 | print FILENAME 显示处理的文件。 |
| ARGC / ARGV | 参数数量和数组。 | 用于访问命令行参数。 |
4. 特殊块
awk 支持特殊模式块,这些块不依赖输入行:
-
BEGIN {动作}:在处理任何输入前执行一次,常用于初始化变量、打印表头。
-
END {动作}:在处理所有输入后执行一次,常用于汇总、打印总计。
-
示例:
awk 'BEGIN {print "Start"} {print $1} END {print "End"}' file.txt
5. 模式和条件
- 正则匹配:/pattern/ 或 n \~ /pattern/。 示例:awk '/error/ {print 0}' log.txt 打印含 "error" 的行。
- 关系运算:==、!=、> 等。 示例:awk '2 \> 100 {print 1}' data.txt 第二字段 >100 的行打印第一字段。
- 逻辑运算:&&、||、!。
- 范围模式:pattern1, pattern2 从 pattern1 到 pattern2 的行。 示例:awk '/start/, /end/' file.txt。
6. 动作和函数
-
print:简单输出。print 1, 2(逗号自动加 OFS)。
-
printf:格式化输出,如 C 风格。printf "%-10s %d\n", 1, 2(左对齐字符串,整数)。
-
内置函数 :
- 字符串:length(str)、substr(str, start, len)、index(str, sub)、tolower(str)、gsub(regex, repl, str)。
- 数学:int(x)、sqrt(x)、rand()、sin(x) 等。
- 时间:systime()、strftime(format, timestamp)(gawk)。
-
控制结构:if-else、for、while、do-while、break、continue。
-
数组 :关联数组(哈希)。arr[key] = value;遍历 for (key in arr)。 示例:统计单词出现次数。
awk '{for(i=1;i<=NF;i++) count[$i]++} END {for(word in count) print word, count[word]}' file.txt
7. 示例应用
-
提取列:awk '{print $2}' file.txt > column2.txt。
-
求和:awk '{sum += $1} END {print sum}' numbers.txt。
-
过滤:awk -F "," '3 == "active" {print 1}' users.csv。
-
替换:awk '{gsub(/old/, "new", $0); print}' file.txt。
-
多文件处理:awk 'FNR==1 {print FILENAME} {print $0}' file1.txt file2.txt。
-
复杂脚本 :计算平均值。
awk 'BEGIN {sum=0; count=0} {sum += $1; count++} END {if(count>0) print sum/count}' data.txt
8. 高级特性(gawk 扩展)
- 多维数组:arr[x,y] = value(实际是 arr["x\034y"])。
- 网络编程:/inet/tcp 等(用于 socket)。
- 扩展函数:用户定义函数 function name(args) {body}。
- include:@include "file.awk" 包含其他脚本。
9. 注意事项
- awk 默认忽略前导/尾随空格。
- 处理大文件高效,但脚本复杂时考虑 Perl 或 Python。
- 调试:用 print 插入检查点,或 gawk 的 --dump-variables。
- 兼容性:标准 awk (POSIX) vs gawk(检查 awk --version)。