提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档
文章目录
- 前言
- 一、概述
-
- [1.1 什么是 AWK?](#1.1 什么是 AWK?)
- [1.2 应用场景](#1.2 应用场景)
- 二、工作原理
-
- [2.1 逐行处理机制](#2.1 逐行处理机制)
- [2.2 awk 与 sed 的区别](#2.2 awk 与 sed 的区别)
- 三、基本语法与命令格式
-
- [3.1 命令格式](#3.1 命令格式)
- [3.2 常用选项](#3.2 常用选项)
- 四、内置变量
- 五、常用操作示例
-
- [5.1 打印整行或指定字段](#5.1 打印整行或指定字段)
- [5.2 内建变量](#5.2 内建变量)
- 扩展生产案列:网卡的ip、流量
- [5.3 BEGIN END 运算](#5.3 BEGIN END 运算)
-
- [5.3.1 awk的运算](#5.3.1 awk的运算)
- [5.3.2 模糊匹配](#5.3.2 模糊匹配)
- [5.3.3 关于数值与字符串的比较](#5.3.3 关于数值与字符串的比较)
- [5.3.4 逻辑运算](#5.3.4 逻辑运算)
- 5.3.5其他内置变量的用法FS(输入)、OFS、NR、FNR、RS、ORS
- [5.4 awk高级用法 if语句](#5.4 awk高级用法 if语句)
- [5.5 BEGIN END 流程](#5.5 BEGIN END 流程)
- 总结
前言
awk 是一种文本处理编程语言,诞生于 1977 年,由贝尔实验室的 Alfred Aho、Peter Weinberger 和 Brian Kernighan 共同设计(名称取自三人姓氏首字母)。它最初用于处理 Unix 系统中的文本数据,如今已成为 Linux/UNIX 环境下数据提取、分析和报告生成的核心工具之一。
awk 的核心设计理念是:"按行处理文本,按字段分割数据"。它无需编译,直接解释执行,支持模式匹配、条件判断、循环、内置函数等编程语言特性,尤其擅长处理结构化文本(如日志文件、配置文件、CSV 数据等)。
与 grep(仅匹配文本)、sed(仅流式编辑)相比,awk 更侧重于数据的提取和加工,可以轻松实现 "筛选行 → 提取字段 → 计算 / 格式化 → 输出结果" 的完整流程,是 Shell 脚本中不可或缺的 "数据处理瑞士军刀"
一、概述
1.1 什么是 AWK?
aWK 是一种处理文本文件的语言,是一个强大的文本分析工具。 被设计用于对文本数据进行扫描、过滤、统计和格式化输出。
按行处理文本、提取结构化数据、实现数据转换与分析(输出内容行)
1.2 应用场景
日志分析
数据提取与转换
报表生成
系统监控脚本
二、工作原理
2.1 逐行处理机制
awk 逐行读取输入文本,默认以空格或制表符(Tab)作为字段分隔符,将每行分割成多个字段,并存储到内置变量中。用户可定义模式或条件,对匹配的行执行相应操作。
处理流程如下:
1.读取第一行数据
2.检查是否匹配条件
3.若匹配则执行指定动作
4.继续处理下一行数据
5.默认不自动输出结果
若未定义匹配条件,则默认处理所有行。由于awk内置循环机制,条件匹配次数与动作执行次数完全对应。
2.2 awk 与 sed 的区别
sed 主要用于整行处理;
awk 更倾向于将行拆分为字段后再进行处理,支持更复杂的字段级操作。
awk信息的读入也是逐行读取的,执行结果可以通过print的功能将字段数据打印显示。
在使用awk命令的过程中,可以使用逻辑操作符&&表示"与"、||表示"或"、!表示"非";
还可以进行简单的数学运算,如+、-、*、/、%、^分别表示加、减、乘、除、取余和乘方
sed 最适合做一些简单、直接的文本替换和清理工作。
awk 更适合处理结构化数据,需要提取特定字段或进行计算的场景。
三、基本语法与命令格式
3.1 命令格式
css
awk [options] 'BEGIN{ print "start" } 'pattern{ commands }' END{ print "end"}' file
#其中:BEGIN END 是 AWK 的关键字部,因此必须大写;这两个部分开始块和结束块是可选的
或者:
awk -f 脚本文件 文件1 文件2 ...
3.2 常用选项
-F:指定字段分隔符;
- -v:定义变量;
- -f:指定 AWK 脚本文件。
四、内置变量
awk 包含几个特殊的内建变量(可直接用)如下所示
变量名 说明
FS 输入字段分隔符,默认为空格或制表符
OFS 输出字段分隔符,默认为空格
NF 当前处理的行的字段个数 NF:列的个数
NR 当前处理的行的行号(序数)
FNR 当前文件中的行号(多文件处理时重置)
$0 当前行的完整内容
$n 当前行的第 n 个字段
FILENAME 当前处理的文件名
RS 输入行分隔符,默认为换行符
ORS 输出行分隔符,默认为换行符
五、常用操作示例
5.1 打印整行或指定字段
#awk '{print "hello"}' < /etc/passwd

#awk '{print 1,2}' zz1 //逗号有空格效果

---root@localhost \~# awk -F: '{print 1"\\t"2}' /etc/passwd //用制表符作为分隔符输出

root@localhost \~# awk -F😕 '{print $9}' zz //定义多个分隔符,只要看到其中一个都
算作分隔符
:以 : 和 / 为共同的字段分隔符,提取文件 zz 中每一行的第 9 个字段并打印出来

5.2 内建变量
awk常用内置变量:1、2、NF、NR、$0
$1:代表第一列
$2:代表第二列以此类推
$0:代表整行
NF:一行的列数
NR:行数
root@localhost \~# awk -F: '/root/{print $0}' pass.txt //打印包含root的整行内容
root❌0:0:root:/root:/bin/bash
root@localhost \~# awk -F: '/root/{print $1}' pass.txt //打印包含root的行的第
一列
root
root@localhost \~# awk -F: '/root/{print 1,6}' pass.txt //打印包含root的行的第一
列和第六列
root /root

root@localhost \~# awk -F😕 '{print NF}' zz //打印每一行的列数
root@localhost \~# awk -F😕 '{print NR}' zz //显示行号
root@localhost \~# awk -F: '{print NR}' pass.txt

#awk -F: '{print NR,$0}' pass.txt
读取 pass.txt 文件,为每一行添加行号,并打印出行号和整行内容。

#awk 'NR2' /etc/passwd //打印第二行,不加print也一样,默认就是
打印
#awk 'NR2{print}' /etc/passwd //同上效果

root@localhost \~# awk -F: 'NR==2{print $1}' /etc/passwd //打印第二行的第一列
root@localhost \~# awk -F: '{print $NF}' /etc/passwd //打印最后一列

root@localhost \~# awk 'END{print NR}' /etc/passwd //打印总行数
65
root@localhost \~# awk 'END{print $0}' /etc/passwd //打印文件最后一行

root@localhost \~# awk -F: '{print "当前行有"NF"列"}' zz
当前行有7列
当前行有7列
root@localhost \~# awk -F: '{print "第"NR"行有"NF"列"}' /etc/passwd //第几行有几
列

扩展生产案列:网卡的ip、流量
###扩展生产:网卡的ip、流量
root@localhost \~# ifconfig ens33 | awk '/netmask/{print "本机的ip地址是"$2}'
$本机的ip地址是192.168.245.211
root@localhost \~# ifconfig ens33 | awk '/RX p/{print $5"字节"}'
8341053字节
#根分区的可用量
root@localhost \~# df -h | awk 'NR==2{print $4}'

5.3 BEGIN END 运算
逐行执行开始之前执行什么任务,结束之后再执行什么任务,用BEGIN、END
BEGIN一般用来做初始化操作,仅在读取数据记录之前执行一次
END一般用来做汇总操作,仅在读取完数据记录之后执行一次
5.3.1 awk的运算
root@localhost \~# awk 'BEGIN{x=10;print x}'
#如果不用引号awk就当作一个变量来输出了,所以不需要加$了
10
root@localhost \~# awk 'BEGIN{x=10;print x+1}' /
#BEGIN在处理文件之前,所以后面不跟文件名也不影响
11
root@localhost \~# awk 'BEGIN{x=10;x++;print x}'
11
root@localhost \~# awk 'BEGIN{print x+1}' #
#不指定初始值,初始值就为0,如果是字符串,则默认为空
1
root@localhost \~# awk 'BEGIN{print 2.5+3.5}'
#小数也可以运算
6
root@localhost \~# awk 'BEGIN{print 32}
##^和 都是幂运算


5.3.2 模糊匹配
模糊匹配,用表示包含,!表示不包含
root@localhost \~# awk -F: '/root/' /etc/passwd
#如果后面有具体打印多少列就没法省略print了
root@localhost \~# awk -F: '$1~/root/' /etc/passwd
root@localhost \~# awk -F: '$1~/ro/' /etc/passwd //模糊匹配,只要有ro就匹配上

root@localhost \~# awk -F: ' 7 ! / n o l o g i n 7!~/nologin 7! /nologin/{print 1,7}' /etc/passwd

5.3.3 关于数值与字符串的比较
比较符号:== != <= >= < >
案列
root@localhost \~# awk 'NR5{print}' /etc/passwd
root@localhost \~# awk 'NR5' /etc/passwd
root@localhost \~# awk 'NR<5' /etc/passwd

5.3.4 逻辑运算
&& 和 || 是逻辑运算符,用于组合多个条件并控制程序流程。
&& 要求所有条件都为真时才为真,否则为假。
|| 只要有一个条件为真就为真,全为假时才为假。
root@localhost \~# awk -F: '3\<10 \|\| 3>=1000' /etc/passwd
root@localhost \~# awk -F: '3\>10 \&\& 3<1000' /etc/passwd
root@localhost \~# awk -F: 'NR>4 && NR<10' /etc/passwd


5.3.5其他内置变量的用法FS(输入)、OFS、NR、FNR、RS、ORS
FS:输入字段的分隔符 默认是空格
OFS:输出字段的分隔符 默认也是空格
FNR:读取文件的记录数(行号),从1开始,新的文件重新重1开始计数
RS:输入行分隔符 默认为换行符
ORS:输出行分隔符 默认也是为换行符
root@localhost \~# awk -F: '$3>=1000' /etc/passwd
nfsnobody❌65534:65534:Anonymous NFS User:/var/lib/nfs:/sbin/nologin
shengjie❌1000:1000:shengjie:/home/shengjie:/bin/bash

root@localhost \~# awk 'BEGIN{FS=":"}{print $1}' pass.txt
//在打印之前定义字段 分隔符为冒号

root@localhost \~# awk 'BEGIN{FS=":";OFS="---"}{print 1,2}' pass.txt
#OFS定义了输出时以什么分隔,12中间要用逗号分隔,因为逗号默认被映射为OFS变量,而这个变量默认是 空格
S=":" 将字段分隔符设置为冒号 :。这意味着 awk 会把每行文本按冒号分割成不同的字段(列)
]# awk '{print FNR,$0}' /etc/resolv.conf /etc/hosts //可以看出 FNR的行号在追加当有多个文件时
同时读取 /etc/resolv.conf 和 /etc/hosts 两个文件,为每个文件中的每一行添加其在 "当前文件内的行号",然后打印出这个行号和整行内容。

#awk '{print NR,$0}' /etc/resolv.conf /etc/hosts

5.4 awk高级用法 if语句
awk的if语句也分为单分支、双分支和多分支
root@localhost \~# awk -F: '{if(3\<10){print 0}}' /etc/passwd //第三列小于10的
打印整行
root@localhost \~# awk -F: '{if(3\<10){print 3}else{print $1}}' /etc/passwd
//第三列小于10的打印第三列,否则打印第一列

5.5 BEGIN END 流程
前面已经讲过了 这边可以忽略
awk还支持for循环、while循环、函数、数组等
其他
awk 'BEGIN{ commands } pattern{ commands } END{ commands }'
第一步:运行BEGIN{ commands }语句块中的语句。
第二步:从文件或标准输入(stdin)读取一行。然后运行pattern{ commands }语句块,它逐行扫描
文件,从第一行到最后一行反复这个过程。直到文件所有被读取完成。
第三步:当读至输入流末尾时,运行END{ commands }语句块。
root@localhost \~#awk 'BEGIN{x=0};//bin/bash$/ {x++;print x,KaTeX parse error: Expected 'EOF', got '}' at position 2: 0}̲;END {print x}..." /etc/passwd
BEGIN模式表示,在处理指定的文本之前,需要先执行BEGIN模式中指定的动作; awk再处理指定的文本,之
后再执行END模式中指定的动作,END{}语句块中,往往会放入打印结果等语句
root@localhost \~#awk -F ":" '! ($3<200){print} ' /etc/passwd
#输出第3个字段的值不小于200的行

root@localhost \~#awk 'BEGIN {FS=":"} ;{if($3>=1000){print}}' /etc/passwd
#先处理完BEGIN的内容,再打印文本里面的内容

root@localhost \~#awk -F ":" '{print NR,$0}' /etc/passwd
#输出每行内容和行号,每处理完一条记录,NR值加1

root@localhost \~#sed -n '=;p' /etc/passwd

root@localhost \~#awk -F ":" '7\~"bash"{print 1,47}' /etc/passwd
#输出以冒号分隔且第7个字段中包含/bash的行的第1个字段

root@localhost \~#awk -F: '/bash/ {print $1}' /etc/passwd
root@localhost \~#awk -F":" '(1\~"root") \&\& (NF==7) {print 1, 2 , 2, 2,NF } '
/etc/passwd
#第1个字段中包含root且有7个字段的行的第1、2个字段
从 /etc/passwd 文件中,筛选出 "用户名包含 root" 并且 "整行恰好有 7 个字段" 的行,然后打印出这些行的用户名(第 1 列)、密码占位符(第 2 列)和登录 Shell(最后 1 列)。

root@localhost \~#awk -F ":" '(7!="/bin/bash")\&\&(7!="/sbin/nologin"){print} '
/etc/passwd
#输出第7个字段既不为/bin/bash,也不为/sbin/nologin的所有行
通过管道、双引号调用shell 命令:
root@localhost \~#echo $PATH | awk 'BEGIN{RS=":"};END {print NR}'
#统计以冒号分隔的文本段落数,END{ }语句块中,往往会放入打印结果等语句
root@localhost \~#free -m |awk '/Mem:/ {print int(3/(3+$4)*100)"%"}' #查看当
前内存使用百分比

oMem: 行:代表物理内存(区别于 Swap 交换内存)。
o$3:第 3 列 used(已使用内存,示例中为 2345 MB)。
o$4:第 4 列 free(空闲内存,示例中为 1234 MB)
oint(...):awk 内置函数,对结果取整(舍弃小数部分,示例:65.5 → 65)。
总结
awk 是一款轻量、高效、功能强大的文本处理工具,它将 "文本处理" 与 "编程语言" 特性完美结合,既适合简单的命令行快速操作,也能通过脚本实现复杂的数据处理逻辑。