Linux awk 命令详解
awk 是一种强大的文本处理工具,它不仅仅是简单的命令行工具,更是一门数据驱动的编程语言。其名称取自三位创始人 Alfred Aho、Peter Weinberger 和 Brian Kernighan 的姓氏首字母。awk 擅长对文本文件进行模式扫描、字段分割、数据过滤、格式化输出等操作,是 Linux 文本处理三剑客(grep、sed、awk)之一。
1. 基本语法
awk [选项] '模式{动作}' 文件...
模式:决定何时执行动作,可以是正则表达式、关系表达式、范围模式等。省略模式则对每一行执行动作。
动作:用大括号括起来的一组语句,如 print、printf、赋值、循环等。
选项:常见的有 -F(指定字段分隔符)、-v(定义变量)、-f(从脚本文件读取 awk 程序)等。
示例:打印 /etc/passwd 的第一列(用户名)
awk -F: '{print $1}' /etc/passwd
2. 工作流程
自动从输入文件(或标准输入)读取一行。
按分隔符将行分割成字段,$1、$2... $NF 分别代表第1、2...最后一个字段,$0 代表整行。
依次对每一行匹配模式,若匹配则执行动作。
处理完所有行后,可执行 END 块中的动作。
3. 常用选项详解
4. 内置变量
示例:打印行号、字段数、第一个和最后一个字段
awk '{print NR, NF, $1, $NF}' file.txt
5. 模式和动作
5.1 模式类型
空模式:匹配所有行。
正则表达式:/正则/,如 /^root/ 匹配以 root 开头的行。
关系表达式:NR==10(第10行)、$3 > 100(第3字段大于100)。
范围模式:pattern1, pattern2 从匹配 pattern1 的行开始到匹配 pattern2 的行结束。
BEGIN / END:BEGIN 在处理任何输入之前执行一次;END 在处理完所有输入之后执行一次。
示例:处理第 5 到第 10 行
awk 'NR>=5 && NR<=10 {print $0}' file.txt
或使用范围模式:
awk 'NR==5,NR==10' file.txt
5.2 动作
动作包含在 {} 中,支持:
变量赋值与运算
打印(print、printf)
条件判断(if、else)
循环(while、for、do while)
数组操作
函数调用
示例:根据第二列数值输出不同信息
awk '$2 > 80 {print $1, "优秀"} $2 >= 60 && $2 <= 80 {print $1, "及格"} $2 < 60 {print $1, "不及格"}' scores.txt
6. 字段处理
6.1 自定义分隔符
使用 -F 选项:awk -F: '{print $1}' /etc/passwd
在 BEGIN 中设置 FS:awk 'BEGIN{FS=":"} {print $1}'
支持正则表达式分隔符:awk -F'[ :\t]+' '{print $1}'
6.2 字段引用与修改
字段可以直接赋值,如 $2 = "newvalue",此时 $0 会使用 OFS 重新构建。
6.3 字段数量与最后一个字段
NF:字段总数
$NF:最后一个字段
$(NF-1):倒数第二个字段
7. 控制语句
示例:计算每行数值之和
awk '{sum=0; for(i=1;i<=NF;i++) sum+=$i; print sum}' numbers.txt
8. 数组
awk 支持关联数组(即下标可以是任意字符串)。
创建与赋值:arr["key"] = value
遍历:for (k in arr) { print k, arr[k] }(遍历顺序不确定)
删除:delete arr[key] 或 delete arr(删除整个数组)
常见用法:统计单词出现次数
awk '{for(i=1;i<=NF;i++) count[$i]++} END{for(w in count) print w, count[w]}' file.txt
9. 内置函数
9.1 字符串函数
9.2 数学函数
9.3 时间函数
systime():返回当前系统时间戳(秒)。
strftime([format [, timestamp]]):格式化时间,如 strftime("%Y-%m-%d")。
示例:打印当前日期
awk 'BEGIN{print strftime("%Y-%m-%d %H:%M:%S")}'
10. 自定义函数
用户可定义函数,语法:
function 函数名(参数列表) {
语句
return 返回值
}
函数定义通常放在 BEGIN 之前或单独文件。示例:
awk '
function max(a,b) {
return a>b ? a : b
}
{print max($1,$2)}' file.txt
11. 典型示例
11.1 格式化输出
使用 printf 控制格式,类似 C 语言:
awk '{printf "%-10s %5d\n", $1, $2}' data.txt
11.2 多文件处理
NR 总行号,FNR 当前文件行号,判断当前处理的文件:
awk 'FNR==1{print "File: " FILENAME} {print $0}' file1 file2
11.3 条件统计
统计每列的和:
awk '{for(i=1;i<=NF;i++) sum[i]+=$i} END{for(i=1;i<=NF;i++) print "col" i ":", sum[i]}' data.txt
11.4 去除重复行(保持顺序)
awk '!seen[$0]++' file.txt
11.5 合并行
将两行合并为一行(例如每隔一行拼接):
awk 'NR%2==1{line=$0; next} {print line, $0}' file.txt
11.6 处理 CSV 文件
假设 CSV 用逗号分隔,但字段内可能含有引号。简单的逗号分割:
awk -F, '{print $1, $2}' data.csv
更复杂的 CSV 解析可使用 FPAT 变量(GNU awk):
bash
awk 'BEGIN{FPAT="([^,]+)|(\"[^\"]+\")"} {print $1}' data.csv
11.7 调用外部命令
使用 system() 函数或管道:
awk '{cmd="echo " $1; system(cmd)}' file.txt
或通过 | 将数据发送给外部命令:
awk '{print $1 | "sort"}' file.txt
12. 高级技巧
12.1 多字符分隔符
awk -F'[:;]' '{print $1}' file # 分隔符可以是冒号或分号
12.2 忽略大小写
设置 IGNORECASE=1:
awk 'BEGIN{IGNORECASE=1} /root/ {print}' /etc/passwd
12.3 输出到多个文件
awk '{print > ($1 > 100 ? "high.txt" : "low.txt")}' data.txt
12.4 使用 getline
getline 可读取下一行或从其他文件读取,需谨慎使用:
awk '{if(getline > 0) print $0, "next line:", $0}' file.txt
12.5 调试
打印所有内置变量:awk '{print "NR="NR, "NF="NF, "$0=" $0}' file
使用 -W dump-variables(gawk)在程序结束时打印变量值。
13. 不同 awk 变体
awk:经典版本,如 BSD awk。
nawk:新的 awk(New awk),功能增强。
gawk:GNU awk,功能最丰富,支持更多扩展(如 FPAT、gensub、asort、网络等)。Linux 默认通常是 gawk,调用 awk 命令时实际是 gawk。
检查版本:awk --version
14. 总结
awk 是 Linux 下极为灵活的数据提取和转换工具,掌握它的核心是理解“模式-动作”机制,熟练使用内置变量和函数,并能灵活运用数组和控制流。对于日常文本分析、日志处理、报表生成等任务,awk 往往能一行解决问题,极大提高效率。
建议初学者从简单字段提取开始,逐步学习条件判断、统计汇总、多文件处理,再深入数组和函数。多实践是掌握 awk 的最佳途径。