引言
在 Linux 文本处理三剑客(grep、sed、awk)中,awk 是最强大但也最有学习曲线的工具。与 grep(搜索过滤)和 sed(流编辑)不同,awk 本质上是一门数据驱动的脚本语言,专门用于格式化处理结构化文本。
awk 的名字来源于其三位创始人:Aho、Weinberger 和 Kernighan。它诞生于 1977 年的贝尔实验室,至今仍是 Unix/Linux 系统中不可或缺的数据处理工具。
本文将全面介绍 awk 的核心概念、基本语法和高级用法,帮助你从入门到精通。
一、awk 的工作原理
理解 awk 的工作模型是掌握它的关键。awk 按行处理文本文件,其基本工作流程如下:
- 逐行读取:一次读取输入文件的一行
- 字段分割:将每行按分隔符(默认是空白字符)切分成多个字段
- 模式匹配:检查该行是否匹配指定的模式
- 动作执行:如果模式匹配,执行指定动作
- 重复:处理下一行,直到文件结束
1
| awk 'pattern { action }' input_file
|
如果省略 pattern,则对所有行执行 action。如果省略 { action },则默认打印匹配的行(相当于 { print })。
二、基本用法
2.1 字段引用
awk 使用 $1、$2、$3… 引用第 1、2、3 个字段,$0 表示整行。
1 2 3 4 5
| awk -F: '{ print $1 }' /etc/passwd
awk -F: '{ print $1, $3 }' /etc/passwd
|
2.2 内置变量
awk 提供了丰富的内置变量:
| 变量 |
说明 |
示例值 |
FS |
字段分隔符(Field Separator) |
:、,、空格 |
OFS |
输出字段分隔符 |
默认空格 |
RS |
记录分隔符(Record Separator) |
默认换行符 \n |
ORS |
输出记录分隔符 |
默认换行符 \n |
NR |
当前处理的记录编号(行号) |
1, 2, 3... |
NF |
当前记录的字段数量 |
5, 7... |
$0 |
整条记录(整行) |
root:x:0:0:root:/root:/bin/bash |
$1, $2, ... |
第 1、2 个字段 |
root、x |
FILENAME |
当前输入文件的名称 |
passwd |
2.3 打印与格式化
1 2 3 4 5
| awk '{ print NR, $1, $NF }' /etc/passwd
awk -F: '{ printf "%-15s %s\n", $1, $7 }' /etc/passwd
|
三、模式匹配
3.1 正则表达式
1 2 3 4 5 6 7 8
| awk '/bash/ { print $1 }' /etc/passwd
awk '/^root/ { print $0 }' /etc/passwd
awk '!/^#/ { print $0 }' config.conf
|
3.2 关系表达式
1 2 3 4 5
| awk -F: '$3 > 500 { print $1, $3 }' /etc/passwd
awk -F: '$4 != 100 { print $1, $4 }' /etc/passwd
|
3.3 范围模式
1 2 3 4 5
| awk '/START/, /END/' log.txt
awk 'NR >= 5 && NR <= 10' file.txt
|
3.4 逻辑运算符
awk 支持 &&(与)、||(或)、!(非)逻辑运算:
1 2 3 4 5
| awk -F: '$3 > 100 && $7 == "/bin/bash" { print $1 }' /etc/passwd
awk 'NR > 10 && NR < 20' file.txt
|
四、高级编程特性
4.1 BEGIN 和 END 块
BEGIN 在所有行处理前执行,END 在所有行处理后执行:
1 2 3 4 5
| awk 'BEGIN { count=0 } { count++ } END { print "Total lines:", count }' file.txt
awk 'BEGIN { total=0 } { total += NF } END { print "Avg fields:", total/NR }' file.txt
|
4.2 数组
awk 支持关联数组(类似 Python 的 dict 或 JavaScript 的对象):
1 2 3 4 5 6 7 8 9
| awk -F: ' { shells[$7]++ } END { for (s in shells) { print s, shells[s] } } ' /etc/passwd
|
4.3 条件语句
1 2 3 4 5 6 7 8 9
| awk -F: '{ if ($3 == 0) { print $1, "是超级用户" } else if ($3 < 1000) { print $1, "是系统用户" } else { print $1, "是普通用户" } }' /etc/passwd
|
4.4 循环语句
1 2 3 4 5 6
| awk '{ for (i = 1; i <= NF; i++) { print "字段" i ":", $i } }' file.txt
|
五、实用示例
5.1 日志分析
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| awk '{ status = $9 if (status ~ /^[0-9]+$/) { codes[status]++ } } END { for (c in codes) { print c, codes[c] } }' /var/log/nginx/access.log
awk '$NF > 5 { print $1, $7, $NF }' /var/log/nginx/access.log
|
5.2 CSV 文件处理
1 2 3 4 5
| awk -F, 'NR > 1 { print $1, $3 }' data.csv
awk -F, '{ sum += $2 } END { print "总和:", sum }' data.csv
|
5.3 合并多列输出
1 2 3 4 5
| awk '{ printf "%s ", $1 } END { print "" }' file.txt
awk '{ print $1, $2, $3 | "sort -k2" }' data.txt
|
六、awk 脚本文件
当 awk 程序较长时,可以写入文件执行:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| $ cat calculate.awk
BEGIN { printf "%-10s %10s %10s\n", "名称", "收入", "支出" total_income = 0 total_expense = 0 }
{ printf "%-10s %10.2f %10.2f\n", $1, $2, $3 total_income += $2 total_expense += $3 }
END { printf "%-10s %10.2f %10.2f\n", "合计", total_income, total_expense printf "%-10s %10.2f\n", "结余", total_income - total_expense }
|
使用方式:
1 2 3 4 5 6 7 8
| $ chmod +x calculate.awk $ ./calculate.awk finance.txt 名称 收入 支出 工资 15000.00 5000.00 兼职 3000.00 500.00 投资 800.00 2000.00 合计 18800.00 7500.00 结余 11300.00
|
七、awk 与 grep、sed 配合
实战中,awk 常与其他命令组合使用:
1 2 3 4 5 6 7 8
| grep "ERROR" app.log | awk '{ print $1, $2, $5 }'
sed 's/^[[:space:]]*//' messy.txt | awk '{ print $1, $NF }'
ps aux | awk '$3 > 5.0 { print $2, $3, $11 }' | sort -k2 -rn | head -10
|
八、常见陷阱与注意事项
- 字段分隔符冲突:文件本身包含空格但又想用空格作为分隔符时,连续空格会被当做一个分隔符,这是 awk 的默认行为,通常符合预期
- 数值比较:awk 中的变量默认是字符串,但参与算术运算时会自动转为数值
- 数组遍历顺序:
for (k in arr) 的遍历顺序是不确定的
- 浮点精度:awk 使用双精度浮点数,精度有限
- 大文件处理:awk 是流式处理,内存占用远小于将整个文件读入内存的方案
九、总结
awk 远不止是一个简单的文本处理工具,它是一门小巧而强大的语言。掌握 awk 的核心概念后,你会发现它可以:
- 快速分析日志文件和系统数据
- 生成格式化的统计报告
- 作为 Shell 脚本中的数据处理引擎
- 处理各种结构化文本格式(CSV、TSV、定宽文件等)
三个实用小技巧记住 awk 的精髓:
- BEGIN:处理前的初始化
- body:逐行数据处理(默认块)
- END:处理后的总结
掌握 grep(搜索)、sed(编辑)、awk(分析)这三剑客,你在 Linux 命令行下的文本处理能力将大大提升。
本文由AI辅助生成,内容仅供参考