云计算大数据——shell教程(三剑客之awk)

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档

文章目录


前言

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 个字段并打印出来 ![在这里插入图片描述](https://i-blog.csdnimg.cn/direct/55110960a8c64199a287c3613f72a8ad.png) ### 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 ![在这里插入图片描述](https://i-blog.csdnimg.cn/direct/7873bb31e4f6440d9bfc2428487a639a.png) \[root@localhost \~\]# awk -F\[😕\] '{print NF}' zz //打印每一行的列数 \[root@localhost \~\]# awk -F\[😕\] '{print NR}' zz //显示行号 \[root@localhost \~\]# awk -F: '{print NR}' pass.txt ![在这里插入图片描述](https://i-blog.csdnimg.cn/direct/e8a5f8d2c7cf4fdbb7c61daa82dbf015.png) #awk -F: '{print NR,$0}' pass.txt 读取 pass.txt 文件,为每一行添加行号,并打印出行号和整行内容。 ![在这里插入图片描述](https://i-blog.csdnimg.cn/direct/13d0880abb8f4b08b8e5517f41635afa.png) #awk 'NR2' /etc/passwd //打印第二行,不加print也一样,默认就是 打印 #awk 'NR2{print}' /etc/passwd //同上效果 ![在这里插入图片描述](https://i-blog.csdnimg.cn/direct/34b9086602ed44b18e89e5d29498117a.png) \[root@localhost \~\]# awk -F: 'NR==2{print $1}' /etc/passwd //打印第二行的第一列 \[root@localhost \~\]# awk -F: '{print $NF}' /etc/passwd //打印最后一列 ![在这里插入图片描述](https://i-blog.csdnimg.cn/direct/27ece8a692ed47bb9c5d8bd3dbac8fa6.png) \[root@localhost \~\]# awk 'END{print NR}' /etc/passwd //打印总行数 65 \[root@localhost \~\]# awk 'END{print $0}' /etc/passwd //打印文件最后一行 ![在这里插入图片描述](https://i-blog.csdnimg.cn/direct/f6125aacd5524afba10fd9e561475a6c.png) \[root@localhost \~\]# awk -F: '{print "当前行有"NF"列"}' zz 当前行有7列 当前行有7列 \[root@localhost \~\]# awk -F: '{print "第"NR"行有"NF"列"}' /etc/passwd //第几行有几 列 ![在这里插入图片描述](https://i-blog.csdnimg.cn/direct/b89db829747144fcafc36a36c3f9e85b.png) ### 扩展生产案列:网卡的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}' ![在这里插入图片描述](https://i-blog.csdnimg.cn/direct/011c24bfcfce49ceb57b8c518c4eb524.png) ### 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 3**2} ##\^和** 都是幂运算 ![在这里插入图片描述](https://i-blog.csdnimg.cn/direct/f7d6a34efa124760919501e43289f3c4.png) ![在这里插入图片描述](https://i-blog.csdnimg.cn/direct/90c9239d9b864c9d853530fd4ac73c97.png) #### 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就匹配上 ![在这里插入图片描述](https://i-blog.csdnimg.cn/direct/bc04feed3fb44db3bf9d9551fc5fa941.png) \[root@localhost \~\]# awk -F: ' 7 ! / n o l o g i n 7!\~/nologin 7! /nologin/{print $1,$7}' /etc/passwd ![在这里插入图片描述](https://i-blog.csdnimg.cn/direct/8e6b0c3f97a241c697a93867ff2af671.png) #### 5.3.3 关于数值与字符串的比较 比较符号:== != \<= \>= \< \> 案列 \[root@localhost \~\]# awk 'NR5{print}' /etc/passwd \[root@localhost \~\]# awk 'NR5' /etc/passwd \[root@localhost \~\]# awk 'NR\<5' /etc/passwd ![在这里插入图片描述](https://i-blog.csdnimg.cn/direct/71e928d1bdee402297d3f4d8fe4b23c7.png) #### 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 ![在这里插入图片描述](https://i-blog.csdnimg.cn/direct/6913a206d650430d967bb48043a93e0f.png) ![在这里插入图片描述](https://i-blog.csdnimg.cn/direct/f36bada9a0b1466e924e8e9171919745.png) ### 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 ![在这里插入图片描述](https://i-blog.csdnimg.cn/direct/d0759bd0262b4c8a8812e4c00927c29f.png) \[root@localhost \~\]# awk 'BEGIN{FS=":"}{print $1}' pass.txt //在打印之前定义字段 分隔符为冒号 ![在这里插入图片描述](https://i-blog.csdnimg.cn/direct/3e5c50f77bef4fc9a185ef3cd6681482.png) \[root@localhost \~\]# awk 'BEGIN{FS=":";OFS="---"}{print $1,$2}' pass.txt #OFS定义了输出时以什么分隔,$1$2中间要用逗号分隔,因为逗号默认被映射为OFS变量,而这个变量默认是 空格 ![在这里插入图片描述](https://i-blog.csdnimg.cn/direct/dbc62ef8d18345f4a0655f7c94eec894.png)S=":" 将字段分隔符设置为冒号 :。这意味着 awk 会把每行文本按冒号分割成不同的字段(列) \]# awk '{print FNR,$0}' /etc/resolv.conf /etc/hosts //可以看出 FNR的行号在追加当有多个文件时 同时读取 /etc/resolv.conf 和 /etc/hosts 两个文件,为每个文件中的每一行添加其在 "当前文件内的行号",然后打印出这个行号和整行内容。 ![在这里插入图片描述](https://i-blog.csdnimg.cn/direct/5a75eac2f6aa4284aa6003465907af5a.png) #awk '{print NR,$0}' /etc/resolv.conf /etc/hosts ![在这里插入图片描述](https://i-blog.csdnimg.cn/direct/5fe491ed640a4bd4ab6a0feb708ec8ec.png) ### 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的打印第三列,否则打印第一列 ![在这里插入图片描述](https://i-blog.csdnimg.cn/direct/91c4dc5b610b448d8c387e4cee226808.png) ### 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的行 ![在这里插入图片描述](https://i-blog.csdnimg.cn/direct/f1c3729337c041f7a83ba6a58f6dbdbc.png) \[root@localhost \~\]#awk 'BEGIN {FS=":"} ;{if($3\>=1000){print}}' /etc/passwd #先处理完BEGIN的内容,再打印文本里面的内容 ![在这里插入图片描述](https://i-blog.csdnimg.cn/direct/5c8b65aadfe449bcb6e425ceb380889b.png) \[root@localhost \~\]#awk -F ":" '{print NR,$0}' /etc/passwd #输出每行内容和行号,每处理完一条记录,NR值加1 ![在这里插入图片描述](https://i-blog.csdnimg.cn/direct/23b2d6817a4d4815ab68c97f0fe6b216.png) \[root@localhost \~\]#sed -n '=;p' /etc/passwd ![在这里插入图片描述](https://i-blog.csdnimg.cn/direct/ed38cbbae326484297287c1edd9394b4.png) \[root@localhost \~\]#awk -F ":" '$7\~"bash"{print $1,47}' /etc/passwd #输出以冒号分隔且第7个字段中包含/bash的行的第1个字段 ![在这里插入图片描述](https://i-blog.csdnimg.cn/direct/0cd1dc4b4db44e50927bdd228f40b488.png) \[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 列)。 ![在这里插入图片描述](https://i-blog.csdnimg.cn/direct/f6a0af56e77d4c9faa51937408b5cc3f.png) \[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)"%"}' #查看当 前内存使用百分比 ![在这里插入图片描述](https://i-blog.csdnimg.cn/direct/745da2a3630e4edea251a9d0bd380193.png) oMem: 行:代表物理内存(区别于 Swap 交换内存)。 o$3:第 3 列 used(已使用内存,示例中为 2345 MB)。 o$4:第 4 列 free(空闲内存,示例中为 1234 MB) oint(...):awk 内置函数,对结果取整(舍弃小数部分,示例:65.5 → 65)。 ## 总结 awk 是一款轻量、高效、功能强大的文本处理工具,它将 "文本处理" 与 "编程语言" 特性完美结合,既适合简单的命令行快速操作,也能通过脚本实现复杂的数据处理逻辑。

相关推荐
加勒比之杰克1 小时前
【C++11】Lambda 表达式、可变参数、emplace_back 系列
开发语言·c++·lambda·emplace_back·可变参数模版
思成不止于此2 小时前
【C++ 数据结构】二叉搜索树:原理、实现与核心操作全解析
开发语言·数据结构·c++·笔记·学习·搜索二叉树·c++40周年
P***25392 小时前
JavaScript部署
开发语言·前端·javascript
Hello.Reader2 小时前
Flink CDC 用 PolarDB-X CDC 实时同步数据到 Elasticsearch
大数据·elasticsearch·flink
come112342 小时前
现代前端技术栈关系详解 (PHP 开发者特供版)
开发语言·前端·php
yong99902 小时前
基于互信息的Matlab多模态医学图像配准实现
开发语言·matlab
说私域3 小时前
智能名片链动2+1模式S2B2C商城小程序:构建私域生态“留”量时代的新引擎
大数据·人工智能·小程序
E***q5393 小时前
JavaScript数据挖掘开发
开发语言·javascript·数据挖掘
Lxinccode3 小时前
python(59) : 多线程调用大模型ocr提取图片文本
开发语言·python·图片提取文字·批量提取文件·多线程ocr