awk 命令速查表 - Linux 文本处理常用命令大全
日志和报表的共同特征是「一行一个字段」,而 awk 的杀手锏正是按列干活:统计 nginx 日志里各状态码占比、按用户分组求和,一条命令顶一段脚本。表从基础语法、内置变量、条件判断、统计与计算、字符串函数到常用场景六组展开,对应完整处理骨架:pattern 加 action 是每行基本结构,BEGIN 与 END 分别负责预处理和收尾汇总。最该先记住的是内置变量:FS 是输入分隔符、OFS 是输出分隔符、NR 是全局行号、NF 是当前行字段数。统计一组的核心是关联数组:count[$9]++ 按字段值计数,sum[group]+=value 按分组累加,配合 END 输出就是一份完整报表。分工要说清:sed 逐行改写而不理解列结构,awk 理解列才能聚合;cut 只取列不做计算。输入 CSV 时用 FPAT 处理引号内的逗号。
典型使用场景
面向做报表统计与日志分析的工程师。awk 与 sed 的分工要记牢:sed 按行改或删,awk 按列取数与计算。本表按基础语法、内置变量、条件判断、统计计算、字符串函数、常用场景六组组织。最实用的三个模式是「取列统计」`awk '{print $1}' | sort | uniq -c | sort -rn`、`按条件取数」`awk '$9 == 500 {print $7}'`,以及 BEGIN/END 块做前后处理——这两块是 awk 与其它文本工具的关键差异。
基础语法 Basic Syntax 6
awk '{print $1}' fileawk -F: '{print $1, $3}' /etc/passwdawk '{print $1, $NF}' fileawk '{print NR, $0}' fileawk 'NR==10' fileawk 'NR>=10 && NR<=20' file内置变量 Built-in Variables 8
$0$1, $2, $NFNRNFFSOFSRSORS条件判断 Conditionals 6
awk '$3 > 100' fileawk '$1 == "error"' fileawk '$1 ~ /pattern/' fileawk '$1 !~ /pattern/' fileawk 'NR==1 || $1 > 100' fileawk '$1 == "a" {print $2}' file统计与计算 Statistics 5
awk '{sum += $1} END {print sum}' fileawk '{sum += $1} END {print sum/NR}' fileawk '{count++} END {print count}' fileawk '{count[$1]++} END {for(k in count) print k, count[k]}' fileawk 'BEGIN{max=0} {if($1>max) max=$1} END{print max}' file字符串函数 String Functions 7
length($0)substr($0, 5, 10)index($0, "text")split($0, arr, ":")sub(/old/, "new", $0)gsub(/old/, "new", $0)tolower($0) / toupper($0)常用场景 Common Patterns 5
awk '{print $1}' access.log | sort | uniq -c | sort -rnawk '$9 == 500 {print $7}' access.logawk -F, '{print $2, $3}' data.csvawk 'BEGIN{OFS=","} {print $1, $2}' fileawk '{sum+=$5} END{print sum/1024/1024 " MB"}' file参数矩阵
| 参数 | 作用 | 示例 |
|---|---|---|
{print $1} | 打印第 1 列(默认空白分隔) | awk '{print $1}' file |
-F<sep> | 指定输入分隔符 | awk -F: '{print $1, $3}' /etc/passwd |
$0 | 整行内容 | awk '{print NR, $0}' file |
$NF | 最后一列(列数不定时最有用) | awk '{print $1, $NF}' file |
NR / NF | 当前行号 / 当前行列数 | awk 'NR==10' file |
FS / OFS | 输入 / 输出分隔符 | awk 'BEGIN{OFS=","} {print $1, $2}' file |
$3 > 100 | 数值比较(awk 自动识别数字) | awk '$3 > 100' file |
$1 ~ /pat/ | 正则匹配(!~ 为不匹配) | awk '$1 ~ /^error/' app.log |
BEGIN / END | 处理前 / 处理后执行一次 | awk '{sum+=$1} END {print sum}' file |
sum += $1 | 累加,可结合 END 输出 | awk '{sum+=$1} END {print sum/NR}' file |
count[$1]++ | 关联数组分组计数 | awk '{c[$1]++} END {for(k in c) print k, c[k]}' file |
sub / gsub | 替换第一个 / 全部匹配 | gsub(/old/, "new", $0) |
split / substr | 按分隔符拆数组 / 截取子串 | split($0, arr, ":") |
管道组合 | 与 sort / uniq 组合做统计 | awk '{print $1}' f | sort | uniq -c | sort -rn |
易错点与避坑指南
现象awk 取到的列全是空的或整行被当成一个字段。
原因分隔符不匹配——文件是冒号分隔却没加 -F:,awk 默认按空白切。
处置先用 head 看一眼真实分隔符,再用 awk -F: 或 -F, 指定正确分隔符。
现象sum 统计结果为 0 或异常大。
原因列中含有非数字字符(如单位、时间戳),被按 0 参与运算。
处置用 head 确认数据格式;必要时先 gsub 去掉非数字字符,或改用 $1+0 显式转数。
现象END 块里访问不到累加变量。
原因累加变量在主块与 END 块中的作用域不一致(常见于把变量声明在条件分支内)。
处置在 BEGIN 块里初始化累加器,或确保累加语句在顶层而非某个分支内首次赋值。
现象awk 里的正则匹配不到内容。
原因正则中的特殊字符(. * + ? [ ])需要转义。
处置字面匹配用 /\./ 或 index/substr 代替正则;~ 两侧不要写字符串引号。
现象统计每个项的次数,结果全是 1。
原因管道漏了 sort,awk 的关联数组本身不排序,但未先聚合导致重复项被覆盖。
处置写全四步:awk 提取 | sort | uniq -c | sort -rn。
现象输出列之间连在一起,没有分隔。
原因print 对多个表达式默认用 OFS 分隔,但 OFS 未显式设置且用逗号分隔的写法被当成了字符串拼接。
处置BEGIN{OFS=","} 设置输出分隔符;print $1, $2 用逗号分隔表达式。
现象处理带空格的字段时整行被切开。
原因默认 FS 是空白(含空格与 Tab),字段值内部有空格时会被拆开。
处置把 FS 设为固定单字符:-F" " 或 -F"|"。
排障路径
1先确认数据分隔符与列位置
head -3 file看清真实分隔符再写表达式,能避免大部分「取不到列」的返工。
2统计访问量 TOP 20
awk '{print $1}' access.log | sort | uniq -c | sort -rn | head -20取列 → 排序聚合 → 计数 → 按数值降序,四步缺一不可。
3按条件提取字段
awk '$9 == 500 {print $7}' access.log$9 是状态码、$7 是 URL;条件放前面 {} 放动作。
4计算列总和并换算单位
awk '{sum+=$5} END {print sum/1024/1024 " MB"}' fileEND 块输出结果,字符串拼接单位最直观。
5按第一列分组统计
awk '{c[$1]++} END {for(k in c) print k, c[k]}' fileawk 的数组是关联数组,可直接用任意值做键。
命令示例
按第一列分组计数
awk '{count[$1]++} END {for(k in count) print k, count[k]}' access.log | sort -k2 -rn | headcount[$1]++ 用数组下标做键,逐行累加;END 块在全部读完后统一输出。再接 sort 才能按计数排序——awk 本身不排序。
输出
203.0.113.7 1842 198.51.100.22 931 192.0.2.180 407
求和并换算成 MB
awk '{sum += $5} END {printf "%.2f MB\n", sum/1024/1024}' access.logEND 里用 printf 控制输出精度与单位。除法要逐层写,awk 不支持 1024*1024 这样的幂运算符。
输出
482.31 MB
输出 CSV(设置 OFS)
awk -F, 'BEGIN{OFS=","} NR>1 {print $2, $3}' data.csv > out.csv-F, 指定输入分隔符为逗号,OFS 指定输出分隔符。NR>1 跳过 CSV 的表头行,否则标题也会被写进结果。
常见坑与注意事项
- 字段下标从 1 开始,$0 是整行;$1[0] 这类写法不成立。
- awk 默认按空白分隔,解析 CSV 或冒号分隔文件必须显式 -F,否则会把整行当成一个字段。
- OFS 要在 BEGIN 里设置一次,写在主规则里会被每行重置。
- 处理 CSV 时引号内的逗号会被误当分隔符,简单场景可用 FPAT 进阶处理。
- awk 不做排序,统计完必须接 sort | uniq,否则拿到的是无序结果。
提示
- awk 默认以空格或 Tab 分隔,用 -F 指定其他分隔符。
- BEGIN 块在处理文件前执行,END 块在处理完后执行。
- awk 数组是关联数组(哈希表),键可以是字符串。
- awk -v OFS="\t" '{print $1,$2}' 可以把默认的空格输出改成制表符,直接粘进 Excel 不串列。
- awk '{print NR": "$0}' 给每行加行号,排查「输出的第几行不对」时比用 nl -ba 更省一道管道。
- NR 与 FNR 的区别在处理多文件时最有用:NR 是跨文件累计行号,FNR 是当前文件内的行号,用 FNR>1 跳过每个文件的首行表头。
常见问题
awk 的 $1 从 1 开始还是从 0 开始?
从 1 开始。$0 表示整行,$1 是第一个字段,$2 是第二个,以此类推,$NF 是最后一个字段。这个设计容易和数组下标混淆——数组同样是 arr[1] 起,但 awk 里 $1 指的是列而不是数组元素,$NF 这种写法在处理不定列数的文件时特别方便。
awk 怎么按分组做统计?
核心是 count 数组加 END 块:awk '{count[$1]++} END {for(k in count) print k, count[k]}' file 会按第一列分组统计出现次数。统计日志里各 IP 的访问量就是 awk '{print $1}' access.log | sort | uniq -c | sort -rn。求和用 awk '{sum += $1} END {print sum}',求平均再除以 NR。
NF 和 $NF 有什么区别?
NF 是当前行的字段数量(一个数字),$NF 是最后一个字段的内容(一个字符串)。这两个经常一起出现在可变列数的场景:NF < 3 时跳过这种格式不对的行,或者用 $(NF-1) 取倒数第二个字段。搞混的话 awk 会直接报类型错误。
awk 里怎么判断字段是否匹配正则?
用 ~ 运算符:awk '$1 ~ /pattern/' file 匹配,awk '$1 !~ /pattern/' file 取反。等价写法是 index($1, "pattern") 做子串查找,但 index 只找固定字符串,不支持正则。需要对整行匹配时直接用 /pattern/ 即可。
awk 怎么把输出变成 CSV?
设置输出分隔符 OFS 即可:awk 'BEGIN{OFS=","} {print $1, $2}' file 会用逗号分隔输出。注意只在 BEGIN 块里设一次,不要放进主规则,否则会被反复重置。想要带引号的 CSV 输出,可以额外加 OFS 与引号变量并在 print 时手动拼接。
由 巧匠 维护
公开更新于 2026年7月21日,内容持续校对官方文档。