云计算大数据——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 个字段并打印出来

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 是一款轻量、高效、功能强大的文本处理工具,它将 "文本处理" 与 "编程语言" 特性完美结合,既适合简单的命令行快速操作,也能通过脚本实现复杂的数据处理逻辑。

相关推荐
z落落12 小时前
C# ToCharArray + foreach遍历 + String与StringBuilder
开发语言·c#
狒狒热知识13 小时前
2026年AI传播新闻软文营销发布当下178软文网领衔发展路径
大数据·人工智能
学代码的真由酱13 小时前
Java多用户一对一网页聊天室-测试报告
java·开发语言·功能测试·测试
人道领域13 小时前
【LeetCode刷题日记】669.修剪二叉搜索树
开发语言·python·算法
xiaoshuaishuai813 小时前
C# AvaloniaUI动态显示图片
开发语言·c#
出海小龙13 小时前
B2B 跟 B2C 的联盟营销有何根本区别?以及分别如何真正推动增长?
大数据·人工智能
QiLinkOS14 小时前
【从实验室到商业战场:发明专利如何重塑科技与企业的共生生态】
大数据·c语言·数据结构·c++·人工智能·单片机·算法
不做无法实现的梦~14 小时前
git指令速查
大数据·elasticsearch·搜索引擎
日光明媚14 小时前
一步生成视频!One-Forcing:DMD + 零成本 GAN,训练 200 步超越多步 SOTA
android·开发语言·kotlin