awk 命令详解与参数实测(Ubuntu 22.04)

awk 命令逐参数实测详解:按列取值、分隔符、内置变量、BEGIN/END、模式匹配、printf、关联数组统计与字符串函数,全部命令与回显在 Ubuntu 22.04(GNU Awk 5.1.0)实测通过。

Linux命令Linux系统UbuntuUbuntu 22.04命令行文本处理2026/10/15

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:单引号内写正则含 / 要转义吗? 模式中 / 需写成 \/(如匹配路径);或把正则存入变量再用 ~ 匹配。

六、参考链接