在 Linux 四剑客中,find 擅长找文件,grep 擅长过滤,sed 擅长替换,而 awk 则是当之无愧的"全能王"——它不仅能过滤、取行,更能取列、统计计算、条件判断,甚至支持循环和数组。严格来说,awk 不仅是一个命令,更是一门单行脚本语言。本文从基础格式讲到统计计算,配合 11 个实战案例,帮你彻底掌握 awk 这把最强利器。
一、四剑客定位对比
| 剑客 | 核心特长 | 擅长场景 |
|---|
find | 查找文件 | 按名称/大小/时间定位文件,与其他命令配合 |
grep / egrep | 过滤 | 过滤速度最快,快速定位包含关键字的行 |
sed | 替换、取行 | 批量替换文本、修改文件内容 |
awk | 取列、统计计算 | 取行取列、条件判断、统计求和、格式化输出 |
awk 的核心优势在于列处理能力——其他三个剑客都无法直接按列提取和运算。
二、awk 基本格式
awk [选项] '条件{动作}' 文件条件:找谁(哪些行满足要求)
动作:干啥(对满足条件的行做什么操作)
示例: 取出 /etc/passwd 第 1 行的第 1 列、第 3 列和最后一列:
awk -F: 'NR==1{print $1,$3,$NF}' /etc/passwd# 选项 条件 动作 文件执行流程
awk 逐行读取文件 │ ▼ 当前行是否满足条件? │ ┌───┴───┐ 是 否 │ │ ▼ ▼执行动作 跳过,读下一行 │ ▼输出结果
三、取行
案例 1:取出指定行
# 取出 /etc/passwd 的第 1 行awk 'NR==1' /etc/passwd# 输出:root:x:0:0:root:/root:/bin/bash
知识点解析:
| 元素 | 含义 |
|---|
NR | Number of Record,记录号(即行号) |
== | 等于 |
{print $0} | 输出整行内容($0 表示当前行),满足条件后的默认动作,可省略 |
案例 2:取出范围行
# 取出第 2 行到第 5 行awk 'NR>=2 && NR<=5' /etc/passwd
awk 常用运算符
| 运算符 | 说明 | 示例 |
|---|
== | 等于 | NR==1 |
!= | 不等于 | NR!=1 |
> | 大于 | $3>100 |
>= | 大于等于 | NR>=2 |
< | 小于 | $3<100 |
<= | 小于等于 | NR<=5 |
&& | 并且(AND) | NR>=2 && NR<=5 |
\|\| | 或者(OR) | NR==1 \|\| NR==3 |
! | 取反(NOT) | !/root/ |
案例 3:按内容过滤行
# 过滤出包含 root 或 nobody 的行awk '/root|nobody/' /etc/passwd
案例 4:范围过滤
# 从包含 root 的行到包含 nobody 的行(包含首尾)awk '/root/, /nobody/' /etc/passwd
取行小结
| 方法 | 说明 | 示例 |
|---|
NR==N | 取指定行 | awk 'NR==1' |
NR>=M && NR<=N | 取范围行 | awk 'NR>=2 && NR<=5' |
/正则/ | 过滤包含内容的行 | awk '/root/' |
/开始/,/结束/ | 范围过滤 | awk '/root/,/nobody/' |
四、取列
这是 awk 最核心的能力,也是区别于其他工具的关键。
案例 5:取出指定列
# 取出 ls -lh 结果的大小列(第5列)和文件名列(最后一列)ls -lh /etc/hosts | awk '{print $5,$NF}'# 输出:158 /etc/hosts列相关的变量:
| 变量 | 含义 |
|---|
$1 | 第 1 列 |
$2 | 第 2 列 |
$N | 第 N 列 |
$0 | 整行内容 |
$NF | 最后一列(NF = Number of Field,字段总数) |
$(NF-1) | 倒数第 2 列 |
NF | 当前行的列数 |
实用示例: 从安全日志中提取密码错误的 IP 地址:
grep 'Failed' /var/log/secure | awk '{print $(NF-3)}'输出对齐
awk 输出多列时默认用空格分隔,可以用以下方式对齐:
# 方法一:使用 column 命令对齐ls -lh | awk '{print $5,$NF}' | column -t# 方法二:使用 \t(Tab)分隔ls -lh | awk '{print $5"\t"$NF}' 案例 6:指定分隔符取列
awk 默认以空白字符(空格、连续空格、Tab)为分隔符。对于 /etc/passwd 这种以冒号分隔的文件,需要用 -F 手动指定:
# 取出用户名(第1列)、UID(第3列)和 Shell(最后一列)awk -F ':' '{print $1,$3,$NF}' /etc/passwd | column -t分隔符选择技巧: 看你想取的目标字段两边是什么字符,那个字符就是分隔符。
案例 7:复杂分隔符提取 IP 地址
这是 awk 的经典面试题——从 ip a 输出中提取 IP 地址:
# 原始数据(第3行)ip a s eth0 | awk 'NR==3'# inet 192.168.2.200/24 brd 192.168.2.255 scope global eth0
方法一:逐步拆解(初学者思路)
ip a s eth0 | awk 'NR==3' | awk '{print $2}' | awk -F '/''{print $1}'# 192.168.2.200方法二:使用字符类分隔符
# [ /] 表示遇到空格或 / 就切一刀(4个空格切4刀,IP 在第6列)ip a s eth0 | awk 'NR==3' | awk -F '[ /]''{print $6}'# [ /]+ 表示遇到连续的空格或 / 切一刀(4个空格切1刀,IP 在第3列)ip a s eth0 | awk 'NR==3' | awk -F '[ /]+''{print $3}'方法三:使用字符串分隔符
# 用 "inet " 和 "/24" 作为分隔符,IP 在第2列ip a s eth0 | awk 'NR==3' | awk -F 'inet |/24''{print $2}'分隔符小结
| 场景 | 做法 |
|---|
| 空格/Tab 分隔 | 直接取列,无需 -F |
固定字符分隔(如 :;) | -F':' |
| 多种字符分隔 | -F'[ /]'(字符类) |
| 连续分隔符合并 | -F'[ /]+'(加 + 号) |
| 字符串分隔 | -F'inet \|/24'(用 \| 分隔多个字符串) |
五、取行 + 取列
真正的实战中,取行和取列通常需要组合使用。
案例 8:一步到位提取 IP
# 条件:第3行 动作:取第3列 分隔符:连续空格或/ip a s eth0 | awk -F '[ /]+''NR==3{print $3}'# 192.168.2.200额外示例: 提取文件权限的数字部分(如 0644):
stat /etc/hosts | awk -F '[/(]''NR==4{print $2}'# 或者用非数字作为分隔符stat /etc/hosts | awk -F '[^0-9]+''NR==4{print $2}'案例 9:按列的值过滤行
取出 /etc/passwd 中 UID 大于 100 的用户,显示用户名、UID 和 Shell:
# 只看条件awk -F ':' '$3>=100' /etc/passwd# 条件 + 动作awk -F ':' '$3>=100{print $1,$3,$NF}' /etc/passwd | column -t这就是 awk 的威力——对某一列进行数值比较和过滤,grep 和 sed 做不到。
案例 10:多条件组合判断
检查系统 swap 使用情况:
# 条件:Swap 行 且 第3列(已使用)大于 0 free | awk '/Swap/ && $3>0 {print "Warning: swap is being used!"}'案例 11:对某一列进行正则匹配
取出 /etc/passwd 中第 4 列(GID)以 0 或 1 开头的行:
awk -F ':' '$4 ~ /^[01]/ {print $1,$3,$4}' /etc/passwd列匹配操作符:
| 操作符 | 含义 | 示例 |
|---|
~ | 包含(正则匹配) | $1 ~ /root/ 第1列包含 root |
!~ | 不包含 | $1 !~ /nologin/ 第1列不包含 nologin |
六、统计与计算
awk 的计算能力是它被称为"语言"的重要原因。
BEGIN 与 END
| 块 | 执行时机 | 用途 |
|---|
BEGIN{} | 读取文件之前执行一次 | 初始化变量、打印表头 |
{...} | 每读取一行执行一次 | 主逻辑 |
END{} | 读取完所有行后执行一次 | 输出汇总结果 |
awk 'BEGIN{print "开始处理"} {处理每一行} END{print "处理完成"}' file统计行数(计数)
原理:i=i+1,每读一行 i 加 1,最后输出 i:
# 统计 /etc/passwd 有多少行(等效于 wc -l)awk '{i=i+1} END {print i}' /etc/passwd# 26# 简写awk 'END{print NR}' /etc/passwd# 26计算过程演示:
| 行数 | i 的初始值 | 执行 i=i+1 | i 的最终值 |
|---|
| 第 1 行 | 0(空/未定义) | i=0+1 | 1 |
| 第 2 行 | 1 | i=1+1 | 2 |
| 第 3 行 | 2 | i=2+1 | 3 |
| ... | ... | ... | ... |
| 第 N 行 | N-1 | i=(N-1)+1 | N |
求和
# 统计 /etc/passwd 中所有用户 UID 的总和awk -F ':' '{sum=sum+$3} END{print sum}' /etc/passwd# 简写为 +=awk -F ':' '{sum+=$3} END{print sum}' /etc/passwd求平均值
# 所有用户 UID 的平均值awk -F ':' '{sum+=$3} END{print sum/NR}' /etc/passwd补充:条件统计
# 统计 UID 大于 100 的用户有多少个awk -F':' '$3>100{count++} END{print count}' /etc/passwd# 统计 /var/log/ 下所有 .log 文件的总大小ls -l /var/log/*.log | awk '{sum+=$5} END{print sum/1024/1024" MB"}'补充:数组统计(进阶)
awk 数组是统计分析的利器,最经典的应用是统计每个元素出现的次数:
# 统计每个 Shell 被多少用户使用awk -F ':' '{shell[$NF]++} END {for(s in shell) print s, shell[s]}' /etc/passwd# /bin/bash 3# /sbin/nologin 18# /bin/sync 1# 统计 Nginx 日志中每个 IP 的访问次数,取 Top 10awk '{ip[$1]++} END{for(i in ip) print ip[i], i}' access.log | sort-rn | head -10
七、补充:awk 内置变量速查
| 变量 | 含义 |
|---|
NR | 当前行号(Number of Record) |
NF | 当前行的列数(Number of Field) |
$0 | 当前行的全部内容 |
$N | 第 N 列 |
$NF | 最后一列 |
FS | 输入字段分隔符(等效于 -F,默认空白) |
OFS | 输出字段分隔符(默认空格) |
RS | 输入记录分隔符(默认换行) |
ORS | 输出记录分隔符(默认换行) |
FILENAME | 当前处理的文件名 |
FNR | 当前文件的行号(处理多文件时有用) |
OFS 示例: 控制输出分隔符:
# 用逗号分隔输出(生成 CSV)awk -F ':' 'BEGIN{OFS=","} {print $1,$3,$NF}' /etc/passwd# root,0,/bin/bash# bin,1,/sbin/nologin
八、补充:格式化输出 printf
print 输出简单但格式不可控,printf 可以精确控制格式:
# 格式化输出用户名和 UID,左对齐,固定宽度awk -F ':' '{printf "%-15s %-6s %s\n", $1, $3, $NF}' /etc/passwd# root 0 /bin/bash# bin 1 /sbin/nologin| 格式符 | 含义 |
|---|
%s | 字符串 |
%d | 整数 |
%f | 浮点数 |
%-15s | 左对齐,宽度 15 的字符串 |
\n | 换行(printf 不自动换行) |
九、知识体系总结
awk '条件{动作}' 文件 │ │ │ ├── print $1,$3,$NF 取列 │ ├── print $0 输出整行 │ ├── i++; sum+=$3 统计计算 │ └── printf "%-10s", $1 格式化输出 │ ├── NR==1 取指定行 ├── NR>=2 && NR<=5 取范围行 ├── /root/ 正则过滤行 ├── $3>=100 按列值过滤 └── $4 ~ /^[01]/ 按列正则匹配选项:-F':' 指定分隔符特殊块:BEGIN{} 读取前执行 END{} 读取后执行掌握优先级:
核心:取行(NR)与取列($N, $NF)
熟练:对列进行数值比较($3>=100)
熟悉:对列进行正则匹配($4 ~ /^[01]/)
进阶:统计计算(计数、求和、数组统计)
写在最后
至此,Linux 四剑客系列已全部集结:
| 篇目 | 核心能力 | 一句话总结 |
|---|
| find | 查找文件 | 按名称/大小/时间精准定位,三种组合技配合其他命令 |
| grep | 过滤文本 | 速度最快的行过滤工具,正则表达式的最佳搭档 |
| sed | 替换修改 | 流编辑器,批量替换文本内容的瑞士军刀 |
| awk | 取列计算 | 最强文本处理语言,取列+统计+判断无所不能 |
四剑客各有所长,组合使用威力倍增。掌握它们,日常运维中 90% 的文本处理需求都能轻松应对。
关注本公众号,更多 Linux 实战内容持续更新。
觉得有用?转发给你的运维/开发同事,一起修炼内功。