阶段十二:Shell脚本之Shell三剑客
一、Shell三剑客概述
1. Shell三剑客
Shell三剑客是指grep、sed和awk这三个在Linux/Unix系统中常用的命令行工具。
grep:grep 是一个文本搜索工具,用于根据给定的模式(正则表达式)在文件或输入流中搜索匹配的行。grep 的主要作用是查找和过滤特定文本。
sed:sed是一个流编辑器,可以对文本进行查找、替换、删除等操作。它可以直接在文本流中编辑,不需要打开文件,非常适合批量处理。
awk:awk 是一个文本处理工具,适合对列进行处理和分析。它不仅可以进行查找和替换,还能执行数学计算和数据统计,特别适合处理以列形式组织的数据,如日志、CSV 文件等。
面试题:grep、sed、awk有何区别?
- grep用于查找特定内容,适合快速过滤日志或配置文件。
- sed 用于修改和编辑文本,非常适合批量替换或删除操作。
- awk 更强大,适用于列状数据的处理,能够提取字段、统计数据或进行数学计算。
在运维工作中,我会根据不同的需求选择合适的工具:当需要简单查找时用 grep,批量修改文件时用 sed,处理复杂的日志或统计数据时使用 awk。
2. Shell三剑客适用场景
① 日志处理与搜索:使用 grep 搜索关键词,结合 sed 和 awk 进行进一步处理和分析。
② 配置文件管理:使用 sed 和 awk 进行批量修改、添加或删除配置项。
③ 数据提取与转换:利用 awk 提取、分析和转换结构化文本数据,处理 CSV、JSON 等格式。
④ 监控与报警:使用 grep、sed 和 awk 提取关键信息生成监控报告,监控系统状态和性能。
⑤ 日常运维任务:自动化任务如查找过期文件、清理日志、统计日志大小等。
⑥ 系统管理:使用 sed 和 awk 处理系统状态信息,如用户信息、进程信息、磁盘使用情况等。
3. Shell三剑客执行说明
默认情况下,grep、sed以及awk在处理数据时默认都是按行处理
二、Shell三剑客之grep指令
1. grep基本语法
grep主要作用:过滤来自一个文件或标准输入匹配模式内容。
除了 grep 外,还有 egrep。egrep 是 grep 的扩展,相当于 grep -E。
基本语法:grep [OPTION]... PATTERN [FILE]...
| 支持的正则 | 描述 |
|---|---|
| -E,--extended-regexp | 模式是扩展正则表达式(ERE) => 字符簇、()、|或 |
| -P,--perl-regexp | 模式是Perl正则表达式 => \d、\w、\s |
| -i,--ignore-case | 忽略大小写 |
| -w,--word-regexp | 模式匹配整个单词 |
| -v,--invert-match | 打印不匹配的行 |
| 输出控制 | 描述 |
|---|---|
| -n,--line-number | 打印行号 |
| -h,--no-filename | 不输出文件名 |
| -o,--only-matching | 只打印匹配的内容 |
| -r,--recursive | 递归目录 |
| -c,--count | 统计匹配行数 |
2. grep案例演示
准备数据集
# vim demo.txt
Hello, this is an example file.
It contains some lines of text.
Let's use grep to search for specific patterns.命令作用:
- 这条命令用于打开并编辑文件。进入编辑器后需要保存退出,修改才会写回文件。
执行结果:
- 编辑器会打开目标文件;保存并退出后文件内容才会改变。
关键参数:
注意事项:
**关键参数:**
**注意事项:**
关键参数:
注意事项:
注: 2代表指定对第2行操作,其他的行忽略; a代表追加的意思,2a即在第2行后追加文本; 2a后面加上空格,然后跟上你想要插入的多行文本即可。这里的每行文本使用"\n"连接就可以写成一行了。
多行增:
注:\n代表换行符小结:
sed默认操作文件内容是在内存中的模式空间中进行实现,不会影响原文件内容。
如果希望增加操作影响原文件,可以添加一个选项-i
删除指定行文本。
这个功能也是非常得有用,比如我们想删除文件中的某些行,以前最常用的是vi或vim命令,但现在我们知道了sed命令,就应该使用这个高逼格的命令完成任务了。
这里我们需要用到1个sed命令;
"d":删除文本,记忆方法:d的全拼是delete,意思是删除。
因为删除功能比较简单,因此我们结合地址范围一起说明。我们前面学过sed命令可以对一行文本为目标进行处理(在单行前后增加一行或多行文本),接下来我们看一下如何对多行文本为目标操作。
指定执行的地址范围:
sed软件可以对单行或多行文本进行处理。如果在sed命令前面不指定地址范围,那么默认会匹配所有行。 地址用逗号分隔开,n1,n2可以用数字,正则表达式,或者二者的组合表示。
| 地址范围 | 含义 |
|---|---|
| 10 | 对第10行操作 |
| 10,20 | 对10到20行操作,包括第10,20行 |
| 1~2 | first\~step,对1,3,5,7.....行操作 |
| 10,\$ | 对10到最后一行(\$代表最后一行)操作,包括第10行 |
| /Tom/ | 对匹配Tom的行操作 |
| /Tom/,/Alex/ | 对匹配Tom的行到匹配Alex的行操作 |
| /Tom/,\$ | 对匹配Tom的行到最后一行操作 |
| 1,/Alex/ | 对第1行到匹配Alex的行操作 |
案例1:下面用具体的例子演示一下sed删除操作实现
命令说明:如果在sed命令前面不指定地址范围,那么默认会匹配所有行,然后使用d命令删除功能就会删除这个文件的所有内容案例2:
命令说明:这个单行删除想必大家能理解,指定删除第2行的文本
案例3:案例4:
命令说明:在sed软件中,使用正则的格式和awk一样,使用2个"/"包含指定的正则表达式,即"/正则表达式/"。
案例5:
命令说明:这是正则表达式形式的多行删除,也是以逗号分隔2个地址,最后结果是删除包含"Tom"的行到包含"Alex"的行案例6:
命令说明:学过正则表达式后我们知道"$"代表行尾,但是在sed中就有一些变化了,"$"在sed中代表文件的最后一行。因此本例子的含义是删除第3行到最后一行的文本,包含第3行和最后一行,因此剩下第1,2行的内容。
案例7:
命令说明:为了不造成同学们实验文本改来改去导致不同意,因此我用上面的命令语句只是临时修改内存数据,然后通过管道符号传给sed软件。特殊符号~(步长)解析
格式:"first~step"表示从开始,以步长step递增,这个在数学中叫做等差数列 使用:
案例8:
1
2
3
4
5
6
7
8
9
101 3 5 7 9
命令说明:
上面的命令主要验证特殊符号"~"的效果,其他sed命令用法n和p请见后文详解,大家只需要知道这个命令可以将"1~2"指定的行显示出来即可。
上面例子测试了"1~2"的效果,大家也可以手动测试一下"2~2","1~3","2~3",看一下他们的结果是不是符合等差数列。
案例9:删除所有奇数行
命令说明:"1~2"这是指定行数的另一种格式,从第1行开始以步长2递增的行(1,3,5),因此删掉第1,3,5行,即所有的奇数行。命令说明:在地址范围"2,3"后面加上" !",如果不加"!"表示删除第2行和第3行,结果如下面的例子所示,然后加上"!"的结果就是除了第2行和第3行以外的内容都删除,这个方法可以作为显示文件的第2,3行题目的补充方法。
小结:
sed软件不仅可以添加数据行,也可以删除数据行,删除数据行必须使用(d)命令
sed修改操作,我们最常见的操作就是改配置文件,改参数等等
首先说一下按行替换,这个功能用的很少,所以大家了解即可。这里用到的sed命令是:"c":用新行取代旧行,记忆方法:c的全拼是change,意思是替换。
命令说明:使用sed命令c将原来第2行内容替换成106,Smith,CSO,整行替换接下来说的这个功能,有工作经验的同学应该非常的熟悉,因为使用sed软件80%的场景就是使用替换功能。
这里用到的sed命令,选项:
"s":单独使用-->将每一行中第一处匹配的字符串进行替换-->sed命令 "g":每一行进行全部替换-->sed命令s的替换标志之一(全局替换),非sed命令 "-i":修改文件内容-->sed软件的选项,注意和sed命令i区别
sed软件替换模型
路径替换式
s#/home#/root#g
g:global全局替换
sed本身按照进行操作的,如果在1行中有多个要替换的关键词,不加g,则代表只替换满足条件第一个关键词;如果添加g,则代表替换满足条件的所有关键词!注意事项:
**注意事项:**
这个功能也是非常得有用,比如我们想查看文件中的某些行,以前最常用的是cat或more或less命令等,但这些命令有些缺点,就是不能查看指定的行。而我们用了很久的sed命令就有了这个功能了。而且我们前面也说过使用sed比其他命令vim等读取速度更快!
这里我们需要用到1个sed命令
"p":输出指定内容,但默认会输出2次匹配的结果,因此使用-n选项取消默认输出,记忆方法:p的全拼是print,意思是打印。
案例1:
命令说明:选项-n取消默认输出,只输出匹配的文本,大家只需要记住使用命令p必用选项-n。命令说明:
命令说明:查看文件的第2行到3行,使用地址范围"2,3"。取行就用sed,最简单
**注意事项:**
注意:起始值~步长
命令说明:打印文件的1,3,5行。~代表步长注意事项:
命令说明:不指定地址范围,默认打印全部内容。
命令说明:
命令说明:打印含CTO的行到含CFO的行。
注意事项:
命令说明:使用特殊符号"="就可以获取文件的行号,这是特殊用法,记住即可。从上面的命令结果我们也发现了一个不好的地方:行号和行不在一行。
案例9:
命令说明:打印1,2,3行的行号,同时打印输出文件中的内容案例10:取不连续的行
**注意事项:**
作用:awk可以完成复杂的数据分析,如日志分析等等。
awk不仅仅是Linux系统中的一个命令,更可以理解为它是一种编程语言,可以用来处理数据和生成报告(excel)。处理的数据可以是一个或多个文件,可以是来自标准输入,也可以通过管道获取标准输入,awk可以在命令行上直接编辑命令进行操作,也可以编写成awk程序来进行更为复杂的运用。本章主要讲解awk命令的运用。
awk指令是由模式,动作,或者模式和动作的组合组成。
模式既pattern,可以类似理解成sed的模式匹配,可以由表达式组成,也可以是两个正斜杠之间的正则表达式。比如NR==1,这就是模式,可以把他理解为一个条件。
动作即action,是由在大括号里面的一条或多条语句组成,语句之间使用分号隔开。

awk处理的内容可以来自标准输入(<),一个或多个文本文件或管道。

options既参数,使用最多的参数为-F(Field,用于指定字段与字段之间的分隔符,列与列之间的分隔符,默认为空格)
pattern既模式,也可以理解为条件,也叫找谁,你找谁?高矮,胖瘦,男女?都是条件,既模式。
action既动作,可以理解为干啥,找到人之后你要做什么。
模式和动作的详细介绍我们放在后面部分,现在大家先对awk结构有一个了解。
案例1:基本模式与动作
命令说明:案例2:只有模式
bin:x:1:1:bin:/bin:/sbin/nologin daemon:x:2:2:daemon:/sbin:/sbin/nologin adm:x:3:4:adm:/var/adm:/sbin/nologin lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin sync:x:5:0:sync:/sbin:/bin/sync
命令说明: -F指定分隔符为冒号 NR>=2&&NR<=6这部分是条件,表示取第2行到第6行。 但是这里没有动作,这里大家需要了解如果只有条件(模式)没有动作,awk默认输出整行
案例3:只有动作
以下省略....
命令说明:
-F指定分隔符为冒号
这里没有条件,表示对每一行都处理
这里要理解没有条件的时候,awk会处理每一行。案例4:多模式与多动作
命令说明: -F指定分隔符为冒号 这里有多个条件与动作的组合
注意:
Pattern和{Action}需要用单引号引起来,防止Shell作解释。
Pattern是可选的。如果不指定,awk将处理输入文件中的所有记录。如果指定一个模式,awk则只处理匹配指定的模式的记录。
file要处理的目标文件
在深入了解awk前,我们需要知道awk如何处理文件的。
root:x:0:0:root:/root:/bin/bash
bin:x:1:1:bin:/bin:/sbin/nologin
daemon:x:2:2:daemon:/sbin:/sbin/nologin
adm:x:3:4:adm:/var/adm:/sbin/nologin
lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
sync:x:5:0:sync:/sbin:/bin/sync
shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown
halt:x:7:0:halt:/sbin:/sbin/halt
mail:x:8:12:mail:/var/spool/mail:/sbin/nologin
uucp:x:10:14:uucp:/var/spool/uucp:/sbin/nologin注意事项:
bin:x:1:1:bin: daemon:x:2:2:daemon: adm:x:3:4:adm: lp:x:4:7:lp: sync:x:5:0:sync: shutdown:x:6:0:shutdown: halt:x:7:0:halt: mail:x:8:12:mail: uucp:x:10:14:uucp:
命令说明: BEGIN:开始模块,在awk开始处理数据之前执行1次 END:结束模块,在awk处理所有行后执行1次
在每行的开始先打印输出NR(记录号行号),并打印出每一行$0(整行)的内容。 我们设置RS(记录分隔符)的值为“/”,表示一行(记录)以“/”结束 在awk眼中,文件是从头到尾一段连续的字符串,恰巧中间有些\n(回车换行符),\n也是字符哦。
我们回顾下“行(记录)”到底是什么意思?
行(记录):默认以\n(回车换行)结束。而这个行的结束不就是记录分隔符嘛。
所以在awk中,RS(记录分隔符)变量表示着行的结束符号(默认是回车换行)
在工作中,我们可以通过修改RS变量的值来决定行的结束标志,最终来决定“每行”的内容。
为了方便人们理解,awk默认就把RS的值设置为“\n”
注意:
awk的BEGIN模块,我会在后面(模式-BEGIN模块)详细讲解,此处大家仅需要知道在BEGIN模块里面我们来定义一些awk内置变量即可。
对\$0的认识
NR:行号,打印行号
\$NF:NF代表列号,如果前面添加了\$,则代表最后一列
\$0:整行内容
\$1:按照-F分割后,\$1代表分割后的第1列
\$2:按照-F分割后,\$2代表分割后的第2列
由以上代码运行可知:awk中\$0表示整行,其实awk使用\$0来表示整条记录。记录分隔符存在RS变量中或者说每个记录以RS内置变量结束。
另外,awk对每一行的记录号都有一个内置变量NR来保存,每处理完一条记录,NR的值就会自动+1
案例2:NR记录行号
命令说明:
$0表示整行或者说整个记录企业面试题:按单词出现频率降序排序(计算文件中每个单词的重复数量)
**注意事项:**方案二:
**注意事项:**
基本语法:
分隔符,需不需要根据某个符号提取某1列NR存放着每个记录的号(行号)读取新行时候会自动+1
RS是输入数据的记录的分隔符,简单理解就是可以指定每个记录的结尾标志。
RS作用就是表示一个记录的结束
当我们修改了RS的值,最好配合NR(行)来查看变化,也就是修改了RS的值通过NR查看结果,调试awk程序。
ORS输出数据的记录的分隔符
awk学习技巧一则:
大象放冰箱分几步?打开冰箱,把大象放进去,关闭冰箱门。
每条记录都是由多个区域(field)组成的,默认情况下区域之间的分隔符是由空格(即空格或制表符)来分隔,并且将分隔符记录在内置变量FS中,每行记录的区域数保存在awk的内置变量NF中。

OFS输出字段(列)分隔符
案例1:指定分隔符
命令说明: 以:(冒号)为分隔符,显示第2行到第5行之间的第一区域和第三区域。
案例2:提取字符串中的内容注意事项:
命令说明: 通过命令-F参数指定区域分隔符
小技巧:
#默认分隔符时候
#指定分隔符时候
命令说明:
awk默认的FS分隔符对于空格序列,一个空格或多个空格tab都认为是一样的,一个整体。注意事项:
awk无比强大,你可以通过RS,FS决定awk如何读取数据。你也可以通过修改ORS,OFS的值指定awk如何输出数据。

现在你应该会对awk的记录字段有所了解了,下面我们总结一下,学会给阶段性知识总结是学好运维的必备技能。

RS记录分隔符,表示每行的结束标志
NR行号(记录号)
FS字段分隔符,每列的分隔标志或结束标志
NF就是每行有多少列,每个记录中字段的数量
\$符号表示取某个列(字段),\$1\$2\$NF
NF表示记录中的区域(列)数量,\$NF取最后一个列(区域。)
选好合适的刀FS,RS,OFS,ORS
分隔符==>结束标识
记录与区域,你就对我们所谓的行与列,有了新的认识(RS,FS)
awk模式与动作
接下来就详细介绍下,awk的模式都有几种:
案例1:awk正则表达式匹配整行
或
命令解析:
awk只用正则表达式的时候是默认匹配整行的即‘\$0\~/root/’和‘/root/’是一样的。
案例2:awk正则表达式匹配一行中的某一列命令解析:
\$5表示第五个区域(列)
\~表示匹配(正则表达式匹配)
/shutdown/表示匹配shutdown这个字符串
合在一起,\$5\~/shutdown/表示第五个区域(列)匹配正则表达式/shutdown/,既第5列包含shutdown这个字符串,则显示这一行。
案例3:某个区域中的开头和结尾
知道了如何使用正则表达式匹配操作符之后,我们来看看awk正则与grep和sed不同的地方。
awk正则表达式:
| ^ | 匹配一个字符串的开头 |
|---|---|
| \$ | 匹配一个字符串的结尾 |
数据集
**注意事项:**练习题2:显示Xiaoyu的名字和ID号码,并以逗号隔开
练习题3:显示所有以41开头的ID号码的人的全名和ID号码练习题4:显示所有以一个D或X开头的人名全名
练习题5:显示所有ID号码最后一位数字是1或5的人的全名案例4:取出网卡ens33/ens160的ip地址
或
注意事项:
命令解析: |是或者的意思,正则表达式 sort是将输出结果排序 uniq是去重复但不标记重复个数
**注意事项:**

BEGIN模块再awk读取文件之前就执行,一般用来定义我们的内置变量(预定义变量,eg:FS,RS),可以输出表头(类似excel表格名称)
BEGIN模式之前我们有在示例中提到,自定义变量,给内容变量赋值等,都使用过。需要注意的是BEGIN模式后面要接跟一个action操作块,包含在大括号内。awk必须在输入文件进行任何处理前先执行BEGIN里的动作(action)。我们可以不要任何输入文件,就可以对BEGIN模块进行测试,因为awk需要先执行完BEGIN模式,才对输入文件做处理。BEGIN模式常常被用来修改内置变量ORS,RS,FS,OFS等值。
案例1:可以使用BEGIN设定表头信息说明:
要在第一行输出一些username和UID,我们应该想到BEGIN{}这个特殊的条件(模式),因为BEGIN{}在awk读取文件之前执行的。
案例2:awk变量
直接定义,直接使用即可
awk命令不仅可以进行数据获取分析,还支持数学运算!
awk中字母会被认为是变量,如果真的要给一个变量赋值字母(字符串),请使用==双引号==
123456
作用:与BEGIN相呼应,在awk处理文件结束后,会自动触发END模块(只会触发1次)
案例1:统计/etc/servies文件里的空行数量
思路:
grep方法:
16
16
说明:
grep命令-c表示count计数统计包含^$的行一共有多少。注意事项:
提示:
使用了awk的技术功能,很常用
第一步:统计空行个数
/^$/表示条件,匹配出空行,然后执行{i++}(i++等于i=i+1)即:/^$/{i=i+1}第二步:
awk编程思想: 先处理,最后再END模块输出
案例2:awk支持数学运算注意事项:
awk提供了"数组"来存放一组相关的值。
awk是一种编程语言,肯定也支持数组的运用,但是又不同于c语言的数组。数组在awk中被称为关联数组,因为它的下标既可以是数字也可以是字符串。下标通常被称作key,并且与对应的数组元素的值关联。数组元素的key和值都存储在awk程序内部的一张表中,通过一定散列算法来存储,所以数组元素都不是按顺序存储的。打印出来的顺序也肯定不是按照一定的顺序,但是我们可以通过管道来对所需的数据再次操作来达到自己的效果。

students[a]="张三"
students[b]="李四"
students[c]="王五"
白话讲数组:awk数组就和酒店一样。数组的名称就像是酒店名称,数组元素名称就像酒店房间号码,每个数组元素里面的内容就像是酒店房间里面的人。
假设我们有一个酒店:
酒店<===>hotel酒店里面有几个房间110,119,120,114这几个房间
酒店110房间<===>hotel[110] 酒店120房间<===>hotel[120] 酒店119房间<===>hotel[119] 酒店114房间<===>hotel[114]
酒店房间入驻客人
酒店110房间住着xiaoyu<===>hotel[110]="xiaoyu"
酒店119房间住着ruxue<===>hotel[119]="ruxue"
酒店120房间住着dandan<===>hotel[120]="dandan"
酒店114房间住着bingbing<===>hotel[114]="bingbing"案例1:
案例2:
案例3:统计域名访问次数
http://www.itheima.com/index.html http://www.itheima.com/1.html http://post.itheima.com/index.html http://mp3.itheima.com/index.html http://www.itheima.com/3.html http://post.itheima.com/2.html
**注意事项:**第二步:计数
命令说明: i++:i最开始是空的,当awk读取一行,i自身+1
第三步:用数组替换i
命令说明:
2)h[$2]++就等于i++:也就是说我开始给房间里加东西;当出现同样的东西,我就++
4)综上,输出的结果中,每次出现www.itheima.com时,h["www.itheima.com"]就会++。因此最后的输出数字是3第四步:输出最终计数结果
h[www.itheima.com]=3 h[post.itheima.com]=2 h[mp3.itheima.com]=1
http://www.itheima.com/index.html http://www.itheima.com/1.html http://post.itheima.com/index.html http://mp3.itheima.com/index.html http://www.itheima.com/3.html http://post.itheima.com/2.html
针对以上文件,一行一行读取 读取第1行,发现与www.itheima.com这个索引对应的数组元素一致,进行+1 读取第2行,发现与www.itheima.com这个索引对应的数组元素一致,进行+1 ...