Linux 三剑客之 awk

柳三千

文章最后更新时间:2025年06月11日

前言

常见内置变量

$0:代表当前正在处理的整行内容。  
$1, $2, ...:分别表示当前行的第 1 个字段、第 2 个字段,依此类推。  
NF:表示当前行的字段数量。  
NR:表示当前处理的行号。  
FS:输入字段分隔符,默认是空格或制表符,可通过 -F 选项或在 awk 脚本里修改。  
OFS:输出字段分隔符,默认是空格。  

实战训练

基础字段提取

[ldx@VM-20-5-opencloudos ~]$ cat test.txt  
John 25 Engineer  
Alice 30 Manager  
Bob 22 Developer  

# 输出整行  
[ldx@VM-20-5-opencloudos ~]$ awk '{print $0}' test.txt  
John 25 Engineer  
Alice 30 Manager  
Bob 22 Developer  

# 输出所有字段(无分隔符)  
[ldx@VM-20-5-opencloudos ~]$ awk '{print $1 $2 $3}' test.txt  
John25Engineer  
Alice30Manager  
Bob22Developer  

# 自定义输出格式  
[ldx@VM-20-5-opencloudos ~]$ awk '{print "姓名:"$1,"年龄:"$2,"职位:"$3}' test.txt  
姓名:John 年龄:25 职位:Engineer  
姓名:Alice 年龄:30 职位:Manager  
姓名:Bob 年龄:22 职位:Developer  
姓名: 年龄: 职位:  # 最后一行可能为空行  

分隔符修改与指定

[ldx@VM-20-5-opencloudos ~]$ cat test.txt  
John 25 Engineer  
Alice 30 Manager  
Bob 22 Developer  

# 使用 sed 将空格替换为 #  
[ldx@VM-20-5-opencloudos ~]$ sed -i 's/ /#/g' test.txt  
[ldx@VM-20-5-opencloudos ~]$ cat test.txt  
John#25#Engineer  
Alice#30#Manager  
Bob#22#Developer  

# 未指定分隔符时,# 被视为字段内容  
[ldx@VM-20-5-opencloudos ~]$ awk '{print $1,$2}' test.txt  
John#25#Engineer  
Alice#30#Manager  
Bob#22#Developer  

# 通过 -F 指定分隔符为 #  
[ldx@VM-20-5-opencloudos ~]$ awk -F '#' '{print $1,$2}' test.txt  
John 25  
Alice 30  
Bob 22  

行号过滤与字段提取

# 打印第 2-3 行  
[ldx@VM-20-5-opencloudos ~]$ awk 'NR==2,NR==3' test.txt  
Alice#30#Manager  
Bob#22#Developer  

# 读取系统文件并打印 18-21 行(含行号)  
[ldx@VM-20-5-opencloudos ~]$ cat /etc/passwd > test.txt  
[ldx@VM-20-5-opencloudos ~]$ awk 'NR==18,NR==21{print NR,$0}' test.txt  
18 polkitd:x:997:997:User for polkitd:/:/sbin/nologin  
19 rpc:x:32:32:Rpcbind Daemon:/var/lib/rpcbind:/sbin/nologin  
20 rpcuser:x:29:29:RPC Service User:/var/lib/nfs:/sbin/nologin  
21 avahi:x:70:70:Avahi mDNS/DNS-SD Stack:/var/run/avahi-daemon:/sbin/nologin  

# 打印第一列、倒数第二列、最后一列(以 : 分隔)  
[ldx@VM-20-5-opencloudos ~]$ awk -F ':' '{print $1,$(NF-1),$NF}' test.txt  
root /root /bin/bash  
bin /bin /usr/sbin/nologin  
daemon /sbin /usr/sbin/nologin  
...(省略中间行)...  
lighthouse /home/lighthouse /bin/bash  
ldx /home/ldx /bin/bash  

网络地址与输出分隔符设置

# 获取 eth0 接口的 IP 地址  
[ldx@VM-20-5-opencloudos ~]$ ifconfig eth0 | awk 'NR==2{print $2}'  
10.0.20.5  

# 通过 -v 选项设置 OFS 输出分隔符  
[ldx@VM-20-5-opencloudos ~]$ awk -F ":" -v OFS="---" '{print $1,$(NF)}' test.txt  
root---/bin/bash  
bin---/usr/sbin/nologin  
daemon---/usr/sbin/nologin  
...(省略中间行)...  
lighthouse---/bin/bash  
ldx---/bin/bash  

# 设置 OFS 为制表符  
[ldx@VM-20-5-opencloudos ~]$ awk -F ":" -v OFS="\t" '{print $1,$(NF)}' test.txt  
root	/bin/bash  
bin	/usr/sbin/nologin  
daemon	/usr/sbin/nologin  
...(省略中间行)...  

awk 变量

内置变量图示


变量使用示例

# FS:设置输入分隔符为 :  
[ldx@VM-20-5-opencloudos ~]$ awk -v FS=":" '{print $1}' test.txt  
root  
bin  
daemon  

# FNR:文件内相对行号(多文件场景)  
[ldx@VM-20-5-opencloudos ~]$ awk '{print FNR $0}' test.txt system_log.txt  
1root:x:0:0:Super User:/root:/bin/bash  
2bin:x:1:1:bin:/bin:/usr/sbin/nologin  
...(test.txt 行号 1-11)...  
1[2024-01-01 10:00:00] INFO: System started successfully.  
2[2024-01-01 10:05:00] WARN: Disk space is low...  

# RS:修改输入换行符(以 : 分割内容)  
[ldx@VM-20-5-opencloudos ~]$ awk -F ":" -v RS=":" '{print NR $1}' test.txt  
1root  
2x  
30  
...(按 : 分割后逐行输出)...  

# ORS:修改输出换行符(用 ---- 替代)  
[ldx@VM-20-5-opencloudos ~]$ awk -F ":" -v ORS="------" '{print NR $1}' test.txt  
1root------2bin------3daemon------...(连续输出无换行)...  

# FILENAME:获取当前处理的文件名  
[ldx@VM-20-5-opencloudos ~]$ awk -F ":" '{print FILENAME,$1}' test.txt  
test.txt root  
test.txt bin  
test.txt daemon  

# ARGV:获取命令行参数  
[ldx@VM-20-5-opencloudos ~]$ awk -F ":" '{print ARGV[0],ARGV[1],ARGV[2]}' test.txt system_log.txt  
awk test.txt system_log.txt  
awk test.txt system_log.txt  
...(每行都输出参数)...  

# 自定义变量  
[ldx@VM-20-5-opencloudos ~]$ awk -v myname="刘霸天" 'BEGIN{print"我的名字是?" myname}'  
我的名字是?刘霸天  

awk 模式

空模式(处理所有行)

[ldx@VM-20-5-opencloudos ~]$ awk '{print $0}' test.txt  
root:x:0:0:Super User:/root:/bin/bash  
bin:x:1:1:bin:/bin:/usr/sbin/nologin  
...(输出所有行)...  

正则表达式模式

# 匹配包含字母 a 的行  
[ldx@VM-20-5-opencloudos ~]$ cat input.txt  
apple  
banana  
cherry  
date  
[ldx@VM-20-5-opencloudos ~]$ awk '$0 ~ /a/' input.txt  
apple  
banana  
date  

# 匹配不包含字母 a 的行  
[ldx@VM-20-5-opencloudos ~]$ awk '$0 !~ /a/' input.txt  
cherry  

关系表达式模式

# 筛选成绩大于 80 分的学生  
[ldx@VM-20-5-opencloudos ~]$ cat scores.txt  
Alice 85  
Bob 70  
Charlie 90  
David 65  
[ldx@VM-20-5-opencloudos ~]$ awk '$2>80 {print $0}' scores.txt  
Alice 85  
Charlie 90  

范围模式(匹配区间行)

# 匹配日志开始到结束的行  
[ldx@VM-20-5-opencloudos ~]$ cat log.txt  
Start of log  
Line 1  
Line 2  
End of log  
Another line  
[ldx@VM-20-5-opencloudos ~]$ awk '/Start of log/,/End of log/' log.txt  
Start of log  
Line 1  
Line 2  
End of log  

BEGIN 和 END 模式

# 统计成绩总和  
[ldx@VM-20-5-opencloudos ~]$ awk 'BEGIN {sum = 0} {sum += $2} END {print "Total score:", sum}' scores.txt  
Total score: 310  

组合模式(逻辑运算符)

# 筛选成绩在 70-90 分之间的学生  
[ldx@VM-20-5-opencloudos ~]$ awk '$2>70 && $2<90 {print $0}' scores.txt  
Alice 85  

格式化输出

print 与 printf 对比

printf 格式控制示例

# 基础格式化输出  
[ldx@VM-20-5-opencloudos ~]$ cat data.txt  
John 25  
Alice 30  
Bob 22  
[ldx@VM-20-5-opencloudos ~]$ awk '{printf "Name: %s, Age: %d\n", $1, $2}' data.txt  
Name: John, Age: 25  
Name: Alice, Age: 30  
Name: Bob, Age: 22  

# 表格化输出系统用户信息  
[ldx@VM-20-5-opencloudos ~]$ awk -F ":" '
BEGIN{
    printf "%-15s\t %-15s\t %-15s\t %-15s\t %-15s\t %-15s\t %-15s\n",
    "用户名", "密码", "UID", "GID", "用户注释", "用户家目录", "用户使用的解释器"
}
{
    printf "%-15s\t %-15s\t %-15s\t %-15s\t %-15s\t %-15s\t %-15s\n",
    $1, $2, $3, $4, $5, $6, $7
}' test.txt  
用户名              密码              UID              GID              用户注释            用户家目录           用户使用的解释器       
root              x                0                0                Super User        /root              /bin/bash      
bin               x                1                1                bin                /bin               /usr/sbin/nologin  
...(省略中间行)...

总结

  • print:输出格式简单,由 OFS 控制字段分隔,自动添加换行符。
  • printf:通过格式化字符串(如 %-15s 左对齐、%d 整数)实现精细排版,需手动添加换行符 \n
文章版权声明:除非注明,否则均为柳三千运维录原创文章,转载或复制请以超链接形式并注明出处。

取消
微信二维码
微信二维码
支付宝二维码