awk 命令详解与参数实测(Ubuntu 22.04)
awk 命令逐参数实测详解:按列取值、分隔符、内置变量、BEGIN/END、模式匹配、printf、关联数组统计与字符串函数,全部命令与回显在 Ubuntu 22.04(GNU Awk 5.1.0)实测通过。
awk 命令详解与参数实测(Ubuntu 22.04)
目标:全面掌握 awk 的参数与编程要素——按列取值、分隔符、内置变量、BEGIN/END、模式匹配、数组统计与字符串函数,全部命令与回显已在 Ubuntu 22.04(GNU Awk 5.1.0)实测通过。
一、环境信息
- 操作系统:Ubuntu 22.04.5 LTS(x86_64)
- awk 实现:GNU Awk 5.1.0, API: 3.0(
awk --version实测;Ubuntu 22.04 的/usr/bin/awk默认链接到 gawk) - 实测工作目录:
/root/awkdemo/ - 复用目录:
/root/grepdemo/app.log(8 行模拟服务日志)
二、命令概览
2.1 语法与测试数据准备
awk 的基本语法为 awk [选项] '模式{动作}' [文件...]:逐行读入,按分隔符切出字段($1、$2…$NF),对命中模式的行执行动作。测试前准备演示文件:
mkdir -p /root/awkdemo
cat > /root/awkdemo/f.txt <<'EOF'
apple 10 red
banana 20 yellow
cherry 30 red
apple 40 green
EOF
cat > /root/awkdemo/data.csv <<'EOF'
name,score,city
tom,90,beijing
jerry,85,shanghai
spike,78,guangzhou
EOF
cat > /root/awkdemo/etc_passwd.txt <<'EOF'
root:x:0:0:root:/root:/bin/bash
daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin
bin:x:2:2:bin:/bin:/usr/sbin/nologin
EOF
printf 'id\tname\n1\ttom\n2\tjerry\n' > /root/awkdemo/tabtest.tsv
💡 技术拓展:Linux 上的 "awk" 命令有多个实现,语法兼容 POSIX 但扩展能力不同——
实现 特点 典型环境 gawk(GNU awk) 功能最全:数组函数、 -i inplace、TCP/IP 内建、MPFR 高精度Ubuntu/Debian 默认 awk指向它mawk 轻量、解释快,扩展少 部分 Debian 版本默认,嵌入式常用 BusyBox awk 极简实现,覆盖常用子集 Alpine/嵌入式 initramfs nawk(one true awk) BSD 系传统实现 macOS、FreeBSD 本文全部示例在 gawk 5.1.0 下实测;用到 gawk 独有扩展(如
-i inplace)时会显式标注,mawk/BusyBox 环境需自行确认支持。
2.2 --help 全量回显
awk --help 输出选项清单(实测原样保留;awk 的核心是"程序文本"而非参数,参数相对精简):
Usage: awk [POSIX or GNU style options] -f progfile [--] file ...
Usage: awk [POSIX or GNU style options] [--] 'program' file ...
POSIX options: GNU long options: (standard)
-f progfile --file=progfile
-F fs --field-separator=fs
-v var=val --assign=var=val
Short options: GNU long options: (extensions)
-b --characters-as-bytes
-c --traditional
-C --copyright
-d[file] --dump-variables[=file]
-D[file] --debug[=file]
-e 'program-text' --source='program-text'
-E file --exec=file
-g --gen-pot
-h --help
-i includefile --include=includefile
-l library --load=library
-L[fatal|invalid|no-ext] --lint[=fatal|invalid|no-ext]
-M --bignum
-N --use-lc-numeric
-n --non-decimal-data
-o[file] --pretty-print[=file]
-O --optimize
-p[file] --profile[=file]
-P --posix
-r --re-interval
-s --no-optimize
-S --sandbox
-t --lint-old
-V --version
To report bugs, see node `Bugs' in `gawk.info'
which is section `Reporting Problems and Bugs' in the
printed version. This same information may be found at
https://www.gnu.org/software/gawk/manual/html_node/Bugs.html.
PLEASE do NOT try to report bugs by posting in comp.lang.awk,
or by using a web forum such as Stack Overflow.
gawk is a pattern scanning and processing language.
By default it reads standard input and writes standard output.
Examples:
awk '{ sum += $1 }; END { print sum }' file
awk -F: '{ print $1 }' /etc/passwd
2.3 版本确认
$ awk --version | head -2
GNU Awk 5.1.0, API: 3.0 (GNU MPFR 4.1.0, GNU MP 6.2.1)
Copyright (C) 1989, 1991-2020 Free Software Foundation.
三、参数逐项实测
3.1 按列取值:$1、$NF 与 $0
awk 把每行按分隔符切成字段:$1 第 1 列、$NF 最后一列(NF=Number of Fields)、$0 整行:
$ awk '{print $1}' /root/awkdemo/f.txt
apple
banana
cherry
apple
$ awk '{print $1, $NF}' /root/awkdemo/f.txt
apple red
banana yellow
cherry red
apple green
$ awk '{print NR, $0}' /root/awkdemo/f.txt
1 apple 10 red
2 banana 20 yellow
3 cherry 30 red
4 apple 40 green
print $1, $NF 中的逗号让输出自动以空格分隔(OFS)。print NR, $0 相当于给每行加行号,等效 cat -n。
3.2 内置变量 NF:每行字段数
$ awk '{print NF}' /root/awkdemo/f.txt | head -2
3
3
f.txt 每行 3 列故 NF=3。$NF(3.1)就是"取最后一列"的惯用法。
3.3 字段直接参与数值运算
$ awk '{print $2*2}' /root/awkdemo/f.txt
20
40
60
80
awk 是弱类型语言,$2*2 自动把字符串转数字运算,无需显式转换——这是它比 grep/sed 强的地方:取列 + 算数一步完成。
3.4 -F:指定字段分隔符
-F 接单字符、字符串或正则;也支持 -F'\t' 制表符与字符类:
$ awk -F',' '{print $2}' /root/awkdemo/data.csv
score
90
85
78
$ awk -F':' '{print $1, $7}' /root/awkdemo/etc_passwd.txt
root /bin/bash
daemon /usr/sbin/nologin
bin /usr/sbin/nologin
$ awk -F'\t' '{print $1, $2}' /root/awkdemo/tabtest.tsv
id name
1 tom
2 jerry
$ awk -F'[ :]' '{print $1}' /root/grepdemo/app.log | head -2
2026-10-15
2026-10-15
-F','解析 CSV 取第 2 列(分数);-F':'是/etc/passwd分析的标准姿势;-F'\t'解析 TSV(对制表符文件每行 NF=2);-F'[ :]'用字符类正则把"空格或冒号"都当分隔符。
💡 提示:
-F与在 BEGIN 块里赋值FS等价;-F只影响命令行给定的程序,-f脚本文件内应使用BEGIN{FS=...}(见 3.14)。
3.5 BEGIN / END:前后处理块
$ awk 'BEGIN{print "start"} {n++} END{print "lines:", n}' /root/awkdemo/f.txt
start
lines: 4
BEGIN 在读入任何行前执行一次(初始化、打印表头),中间无模式块对每行执行,END 在全部行处理后执行一次(汇总输出)。
3.6 -v:向程序传入变量
$ awk -v threshold=25 '$2 > threshold {print $1, $2}' /root/awkdemo/f.txt
cherry 30
apple 40
-v 变量=值 把 shell 变量安全传入 awk 程序,避免字符串拼接注入问题。阈值 25:cherry 30、apple 40 命中,banana 20 被过滤。
💡 说明:
-v是 shell 与 awk 之间传值的标准通道——把变量写在单引号程序体外面,值里出现引号、$等字符也不会被 shell 二次展开;一次可传多个(-v a=1 -v b=2),程序内 BEGIN 块之前就已生效。
3.7 FS / OFS:输入与输出分隔符
$ awk 'BEGIN{FS=","; OFS=" | "} {print $1, $2}' /root/awkdemo/data.csv
name | score
tom | 90
jerry | 85
spike | 78
FS 控制输入切分(同 -F),OFS 控制 print a, b 的输出连接符——一行把 CSV 改成竖线分隔的报表格式。
3.8 数值累加统计
$ awk 'BEGIN{s=0} {s+=$2} END{print "total:", s}' /root/awkdemo/f.txt
total: 100
$2 求和(10+20+30+40=100),END 块输出汇总。这是 awk '{sum+=$N} END{print sum}' 万能求和模板。
3.9 模式匹配:正则、关系表达式、行号范围、取反
awk 的"模式{动作}"结构中模式可以非常灵活:
$ awk '/red/ {print $1}' /root/awkdemo/f.txt
apple
cherry
$ awk '$3 == "red" {print $1}' /root/awkdemo/f.txt
apple
cherry
$ awk '$2 >= 20 && $2 <= 30 {print $1, $2}' /root/awkdemo/f.txt
banana 20
cherry 30
$ awk 'NR>=2 && NR<=3 {print $1}' /root/awkdemo/f.txt
banana
cherry
$ awk '!/red/ {print $1}' /root/awkdemo/f.txt
banana
apple
/red/对整行做正则匹配;!/red/取反;$3 == "red"精确列匹配(比整行正则更准);$2 >= 20 && $2 <= 30数值区间过滤;NR>=2 && NR<=3按行号取范围,替代sed -n '2,3p'。
3.10 printf:格式化输出
$ awk '{printf "%-8s %6.2f\n", $1, $2/100}' /root/awkdemo/f.txt
apple 0.10
banana 0.20
cherry 0.30
apple 0.40
$ awk 'BEGIN{printf "pi=%.3f\n", 3.14159}'
pi=3.142
%-8s 左对齐占 8 字符宽、%6.2f 右对齐保留 2 位小数——awk 的 printf 与 C 语言同源,适合对齐报表。
3.11 关联数组:分组计数与分组求和
$ awk '{cnt[$3]++} END{for (c in cnt) print c, cnt[c]}' /root/awkdemo/f.txt
red 2
yellow 1
green 1
$ awk '{sum[$1]+=$2} END{for (k in sum) print k, sum[k]}' /root/awkdemo/f.txt
apple 50
banana 20
cherry 30
下标可以是任意字符串的数组(关联数组):第一个示例按第 3 列(颜色)计数,第二个按第 1 列(名称)分组求和(apple 两行 10+40=50)。这是 awk 实现 GROUP BY 的核心手段。
3.12 内置字符串函数
$ awk '{print toupper($1), length($1)}' /root/awkdemo/f.txt
APPLE 5
BANANA 6
CHERRY 6
APPLE 5
$ awk '{sub(/apple/, "APPLE"); print}' /root/awkdemo/f.txt | head -2
APPLE 10 red
banana 20 yellow
$ awk '{gsub(/red/, "RED"); print}' /root/awkdemo/f.txt
apple 10 RED
banana 20 yellow
cherry 30 RED
apple 40 green
$ awk 'BEGIN{split("2026-10-15", a, "-"); print a[1], a[2], a[3]}'
2026 10 15
$ awk 'BEGIN{s=substr("hello world", 7); print s}'
world
$ awk 'BEGIN{print index("hello", "ll")}'
3
$ awk 'BEGIN{print sprintf("%.2f", 1/3)}'
0.33
toupper/tolower大小写转换、length求长度;sub替换每行第一处、gsub替换全部(regex 语义同 sed 的 s/// 与 s///g);split(串, 数组, 分隔)拆字段入数组;substr(串, 起)取子串、index查位置、sprintf格式化成字符串(不打印)。
3.13 if / for 流程控制
$ awk '{if ($2 >= 30) print $1, "high"; else print $1, "low"}' /root/awkdemo/f.txt
apple low
banana low
cherry high
apple high
$ awk 'BEGIN{for (i=1; i<=3; i++) print "iter", i}'
iter 1
iter 2
iter 3
awk 是完整的编程语言:if/else、for、while 都可用,动作块内可写任意复杂逻辑。
3.14 -f:从文件读取 awk 程序
$ cat /root/awkdemo/score.awk
BEGIN { FS = ","; print "== score report ==" }
NR > 1 { total += $2 }
END { printf "total = %d\n", total }
$ awk -f /root/awkdemo/score.awk /root/awkdemo/data.csv
== score report ==
total = 253
程序写入 .awk 文件后用 -f 执行:BEGIN 声明分隔符并打印表头,NR > 1 跳过 CSV 表头行累加分数(90+85+78=253),END 输出合计。复杂逻辑落文件便于复用与维护。
3.15 -i inplace:原地修改文件(gawk 扩展)
$ cp /root/awkdemo/data.csv /root/awkdemo/data-edit.csv && awk -i inplace '{gsub(/tom/, "TOM"); print}' /root/awkdemo/data-edit.csv && head -2 /root/awkdemo/data-edit.csv
name,score,city
TOM,90,beijing
-i inplace(gawk 独有,等价 sed -i)直接改写文件:tom 被替换为 TOM。需要复杂逻辑的原地文本处理时比 sed 顺手。mawk/BusyBox awk 无此扩展。
3.16 --posix:禁用 GNU 扩展
$ awk --posix 'BEGIN{print length("hello")}'
5
--posix 关闭全部 gawk 扩展以验证脚本的可移植性(如 gensub、RT 变量等在 posix 模式不可用)。本例 length() 属 POSIX 标准故正常返回 5;写跨平台脚本时建议最后用 --posix 过一遍。
3.17 管道输入与 exit 退出码
$ printf 'a 1\nb 2\n' | awk '{s+=$2} END{print s}'
3
$ awk 'BEGIN{exit 3}'; echo exit=$?
exit=3
无文件参数时 awk 读标准输入,天然适配管道;程序内 exit N 自定义退出码(默认正常结束为 0),便于在脚本中表达业务状态(如"阈值超标退出 2")。
四、实战示例
4.1 /etc/passwd 账户分析
$ awk -F':' '{print $1, $7}' /root/awkdemo/etc_passwd.txt
root /bin/bash
daemon /usr/sbin/nologin
bin /usr/sbin/nologin
第 1 列用户名与第 7 列登录 shell 一屏列出;统计可登录账户再加条件 /bash$|zsh$/。
4.2 CSV 汇总报表:跳表头 + 分组统计
$ awk -F',' 'NR>1 {sum[$3]+=$2; cnt[$3]++} END{for (c in sum) printf "%-10s avg=%.1f\n", c, sum[c]/cnt[c]}' /root/awkdemo/data.csv
shanghai avg=85.0
guangzhou avg=78.0
beijing avg=90.0
关联数组 + END 块的组合覆盖绝大多数"分组统计"需求:按第 3 列(城市)分组,对第 2 列(分数)求和并除以计数得到均值。注意 for (c in sum) 的遍历顺序与出现顺序无关(见 Q6)。
4.3 日志字段抽取与数值化
$ awk '$3 == "ERROR" {print $1, $NF}' /root/grepdemo/app.log
2026-10-15 db-primary:5432
2026-10-15 db-replica:5432
模式用 $3 == "ERROR" 精确锁定错误级别列(日志每行格式为 日期 时间 级别 ...,级别在第 3 列),抽取日期与主机地址——比整行正则更不易误匹配。
4.4 万能求和模板
$ printf 'a 1\nb 2\n' | awk '{s+=$2} END{print s}'
3
awk '{sum+=$N} END{print sum}' 是系统管理里使用频率最高的一行 awk,配合 ps、du、df 等命令的输出直接做数值汇总。
五、注意事项与常见问题
Q1:$2 打印为空?
分隔符不匹配。默认按连续空白切分;CSV 必须显式 -F',',且注意 -F 写在程序之前(见 3.4)。
Q2:print $1 $2 与 print $1, $2 有何区别?
无逗号是字符串拼接(无间隔);有逗号用 OFS(默认空格)连接(见 3.7)。
Q3:程序里的引号与 shell 引号打架?
单引号包裹整个 awk 程序,程序内部只用双引号;需要 shell 变量时用 -v 传入而不是拼接(见 3.6)。
Q4:-i inplace 报错 fatal: -i is a gawk extension?
当前 awk 是 mawk/BusyBox 实现;安装 gawk(apt install gawk)或改用 awk ... > tmp && mv tmp 原文件 两步法(见 3.15 与 2.1 实现对比)。
Q5:数值变成了字符串拼接结果?
awk 根据上下文自动转换;$2 若含非数字字符,$2+0 可强制转数值。
Q6:for (k in arr) 的输出顺序不稳定?
关联数组遍历顺序未定义;需要排序时先把键收集到数组再用 asort/管道 sort。
Q7:单引号内写正则含 / 要转义吗?
模式中 / 需写成 \/(如匹配路径);或把正则存入变量再用 ~ 匹配。
六、参考链接
- GNU awk 官方手册:https://www.gnu.org/software/gawk/manual/gawk.html
- 本机帮助:
awk --help、man awk(Ubuntu 22.04 内置) - POSIX awk 规范:https://pubs.opengroup.org/onlinepubs/9699919799/utilities/awk.html