三剑客-sed与sort
三剑客-sed&&sort
[TOC]
01.sed
概念

增删改查都会点,
**流编辑器:**就是有许多数据,源源不断的流入编辑器中.一行一行处理.
格式


-
加上-n后
-
小p就行 3p

sed -n
📌 -n 选项:取消默认输出,因为sed默认全部输出.
- 通常用在查找**,模糊匹配上面**
- 有选择的进行过滤, 不让它全部显示
- 删除, 用不到, 没有意义
- 为了显示删除后全部内容
- 这个点, 我们在后面d删除的时候进行详细的演示.**
- -n 通常配置p 来进行选择性的打印输出.


1)查找
小p就行 3p

, 逗号
,逗号表示范围
如果你想要打印前三行,你可以用范围打印, 选择性过滤,记得带选项-n.


$p
📌 sed -n ‘$p’ file
- $本身就表示末尾
- 表示文件的最后一行
案例.输出文件的最后一行
[root@oldboyedu ~]# sed -n '$p' /etc/passwdoperator:x:11:0:operator:/root:/sbin/nologin# 输出文件的最后一行'$本身就表示末尾,表示文件的最后一行'案例.找出文件第3行到最后一行
[root@oldboyedu ~]# sed -n '3,$p' /etc/passwddaemon:x:2:2:daemon:/sbin:/sbin/nologinadm:x:3:4:adm:/var/adm:/sbin/nologinlp:x:4:7:lp:/var/spool/lpd:/sbin/nologinsync:x:5:0:sync:/sbin:/bin/syncshutdown:x:6:0:shutdown:/sbin:/sbin/shutdownhalt:x:7:0:halt:/sbin:/sbin/haltmail:x:8:12:mail:/var/spool/mail:/sbin/nologinoperator:x:11:0:operator:/root:/sbin/nologin# 找出文件第3行到最后一行; 分号隔开
表示同时进行.
同时,如果你不想用范围,只是想要单纯的打印没有规律的三行,比如打印 2,6,7, 行.
不能用 , 逗号
[root@oldboyedu ~]# sed -n '2p;6p;7p' passwd.txt# ;分号隔开没有规律的行


sed ’/ /p’ 模糊过滤
- grep ‘过滤的内容’ file
- sed -n ‘/过滤的内容/p**’ file**
- **/ / **这是一个地址范围(address).用于匹配正则, -r匹配扩展正则
- **p **这是命令,表示打印匹配的行.
- 必须是这个语法才行, ’/ /p’ 否则无法进行模糊匹配
注意:sed 默认全部输出,除非使用 -n 选项抑制默认输出,然后用 p 显式打印

分别用grep和sed过滤以root开头的行.

案例.找出bash结尾的行
[root@test /home]# sed -n '/bash$/p' passwd.txtroot:x:0:0:root:/root:/bin/bash# 找出以bash结尾的行**’/ / Ip’(忽略大小写)
- **I ** 大写这是标志(flag),表示忽略大小写.
[root@oldboyedu ~]# sed -rn '/permitrootlogin|usedns/Ip' /etc/ssh/sshd_config# I 大写, 忽略大小写
区间范围匹配
📌 sed -n ‘/从哪里来/,/到哪里去/p’
- 逗号隔开


案例:从adm的行到sync的行
[root@test /home]# sed -n '/adm/,/sync/p' passwd.txtadm:x:3:4:adm:/var/adm:/sbin/nologinlp:x:4:7:lp:/var/spool/lpd:/sbin/nologinsync:x:5:0:sync:/sbin:/bin/sync# 从adm的行到sync的行, 逗号隔开表示范围
企业中经常匹配日志
[root@oldboyedu ~]# sed -n '/Nov 10 09:54:32/,/Nov 10 10:13:27/p' /var/log/messages# 按照日志中的时间进行过滤- 注意匹配的是日志中存在的时间, 你的日志得有这个时间.
- 注意如果匹配的区间范围只找到开头、则输出从开头的后面所有内容
- 如果有两个开头, 则两个开头后面的内容都输出!
- 如果匹配到一个开头.两个结尾.
- 则以第一个结尾为准输出内容、后面的结尾无效

sed -r
扩展正则用-r选项

案例.过滤包含root或者adm的行,-r支持扩展正则
[root@oldboyedu ~]# sed -rn '/root|adm/p' passwd.txtroot:x:0:0:root:/root:/bin/bashadm:x:3:4:adm:/var/adm:/sbin/nologinoperator:x:11:0:operator:/root:/sbin/nologin# | 表示或者, 扩展正则2)替换
s# # #g

- 前两个#号之间可以用正则**.
- 我们也可以在**#号**前面加 / / 进行正则匹配.
- **/ / **这是一个地址范围(address).用于匹配正则, -r匹配扩展正则
- ‘3,5s#:#@#g’ #把第3行到第5行的所有:替换为@
- ‘/root/s#bash#oldboy#g’ #把包含root行的所有bash替换为oldboy
- 这两条命令下面都有案例
- 因为可以支持正则,还有扩展正则,所以常跟-r选项.
- -n 通常配置p 来进行选择性的打印输出.
- -n ‘1s#root#oldboy#gp’ #1就是第1行,符合并输出.
- 这两个命令,后面也有案例
- -n ‘1p;10s#root#oldboy#gp’ #只过滤第1行和第10行,把替换后的输出
- ;分号没有规律的两行 n,m逗号从第n行到第m行
- 中间是三个成对的东西,可以是###,当然也可以是@@@,都可以的.
- 灵活一点,
- g global 全局替换,这一行中把所有匹配到的内容都进行替换,否则只替换每一行的第一个匹配到的内容.

案例.将:替换成@
[root@oldboyedu ~]# sed 's#:#@#g' passwd.txtroot@x@0@0@root@/root@/bin/bashbin@x@1@1@bin@/bin@/sbin/nologindaemon@x@2@2@daemon@/sbin@/sbin/nologin# 有g则是全局替换'将:替换成@'案例.如果不加g全局替换, 则替换的是每行的第一个:
[root@oldboyedu ~]# sed 's#:#@#' passwd.txtroot@x:0:0:root:/root:/bin/bashbin@x:1:1:bin:/bin:/sbin/nologindaemon@x:2:2:daemon:/sbin:/sbin/nologinadm@x:3:4:adm:/var/adm:/sbin/nologin# 没有g就是只替换匹配到的第一个:'不加g全局替换, 则替换的是每行的第一个'案例.把第3行到第5行的所有:替换为@

案例.把包含root行的所有bash替换为oldboy 这个使用 / / 进行正则匹配


sed -i
⚠️ 如果没有加 -i这个选项,就只是给你看一下修改后的内容,但其实原文件并没有真正的替换.
当-i和-r(扩展正则)组合时 这个-i选项要最后用, -ri 才是正确的 -ir 是错误的
- 只有加上-i后, 源文件才是真正的修改了.
- 因为以后修改配置文件的时候先不要着急修改,先看看没有问题后再加上-i选项.否则容易修改错误.

-i.bak
先备份成.bak;再对原文件进行修改

- 如果原文件特别多,那你就要进行压缩备份了
[root@Rocky10 ~]# cat hh.txthhhfadfa# 原文件的内容[root@Rocky10 ~]# sed -i.bak 's#hhh#xxx#g' hh.txt# 我们实际修改的是原文件的内容[root@Rocky10 ~]# cat hh.txtxxxfadfa# 原文件改变[root@Rocky10 ~]# cat hh.txt.bakhhhfadfa# 这个是备份文件✅️ -i.bak 先备份再修改3)后向引用

- 处理其中某一部分
因为 ( ) 为扩展正则,所以要用sed -r 选项

案例.在第二部分加上<和>




最后一个$写括号()里面或者外面都是可以的.



- 不要记-nr 你只需要知道 这-n和后面的p是紧密结合在一起的
- 表示不输出全部,而是把过滤出来的内容进行打印输出.
- 这个-r对应的是扩展正则,
[root@oldboyedu ~]# ifconfig ens33 | sed -n '2p' | sed -r 's#^.*et (.*) ne.*k (.*) br.*t (.*)$#网络为:\1 子网掩码为:\2 广播地址为:\3#g'# 分步版[root@oldboyedu ~]# ifconfig ens33 | sed -rn '2s#^.*et (.*) ne.*k (.*) br.*t (.*)$#网络为:\1 子网掩码为:\2 广播地址为:\3#gp'# 结合版 ✅️ 一行搞定取IP地址

显示指定网卡,

[root@oldboyedu ~]# ip addr show ens33# 显示指定网卡信息

当然还有更加简便的方法去查看你的ip地址.
用 hostname -I #但是这个IP后面是有一个空格的.别忘了

配合bash
📌 将屏幕上的字符串,当命令使
[root@oldboyedu ~]# echo oldboy | sed -r 's#ol(.*)boy#mkdir \1#g'mkdir d# 输出的字符串是 mkdir d[root@oldboyedu ~]# echo oldboy | sed -r 's#ol(.*)boy#mkdir \1#g' | bash# 相当于执行了 mkdir d, 管道给bash后变为命令执行[root@oldboyedu ~]# lldrwxr-xr-x 2 root root 6 Nov 10 11:45 d# 成功创建了d这个目录✅️ 将sed处理后的字符串通过管道传给bash执行[root@oldboyedu ~]# seq 3123[root@oldboyedu ~]# seq 3 | sed -r 's#(.*)#\1#g'123# 全部都匹配出来,并且拿出来[root@oldboyedu ~]# seq 3 | sed -r 's#(.*)#touch \1#g'touch 1touch 2touch 3# 如果后面再配合 | bash 就会把这些当做命令执行4)d删除

d 删除 因为可以支持正则,还有扩展正则,所以常跟-r选项 删除, 不使用-n选项. 没有意义 -n 通常配置p 来进行选择性的打印输出
d删除是这个样子,替换也是一样的
指定行
- 删除第三行!

- 删除第一行至第三行
识别不出来 - 只能用 , 逗号进行分隔

- 删除没有规律的行,
; 分号 #表示同时进行.
不能用 , 逗号
[root@oldboyedu ~]# sed '2d;6d;7d' passwd.txt# ; 分号表示同时进行, 删除没有规律的行
模糊过滤删除
案例.删除包含root的行
[root@oldboyedu ~]# sed '/root/d' passwd.txtbin:x:1:1:bin:/bin:/sbin/nologindaemon:x:2:2:daemon:/sbin:/sbin/nologinadm:x:3:4:adm:/var/adm:/sbin/nologinlp:x:4:7:lp:/var/spool/lpd:/sbin/nologinsync:x:5:0:sync:/sbin:/bin/syncshutdown:x:6:0:shutdown:/sbin:/sbin/shutdownhalt:x:7:0:halt:/sbin:/sbin/haltmail:x:8:12:mail:/var/spool/mail:/sbin/nologin# 删除包含root的行案例.删除包含root或者adm的行
[root@oldboyedu ~]# sed -r '/root|adm/d' passwd.txtbin:x:1:1:bin:/bin:/sbin/nologindaemon:x:2:2:daemon:/sbin:/sbin/nologinlp:x:4:7:lp:/var/spool/lpd:/sbin/nologinsync:x:5:0:sync:/sbin:/bin/syncshutdown:x:6:0:shutdown:/sbin:/sbin/shutdownhalt:x:7:0:halt:/sbin:/sbin/haltmail:x:8:12:mail:/var/spool/mail:/sbin/nologin# -r 扩展正则, | 表示或者案例.删除以nologin结尾的行
[root@oldboyedu ~]# sed '/nologin$/d' passwd.txtroot:x:0:0:root:/root:/bin/bashsync:x:5:0:sync:/sbin:/bin/syncshutdown:x:6:0:shutdown:/sbin:/sbin/shutdownhalt:x:7:0:halt:/sbin:/sbin/halt# 正常的$正则, 非常简单
案例.按区间范围删除
[root@oldboyedu ~]# sed '/adm/,/halt/d' passwd.txtroot:x:0:0:root:/root:/bin/bashbin:x:1:1:bin:/bin:/sbin/nologindaemon:x:2:2:daemon:/sbin:/sbin/nologinmail:x:8:12:mail:/var/spool/mail:/sbin/nologinoperator:x:11:0:operator:/root:/sbin/nologin# 和上面的查找, 差不多!~ 隔行删除
- 行号从 1 开始计数
1. 删除所有奇数行(保留偶数行)
[root@oldboyedu ~]# sed '1~2d' filename# 1~2:从第1行开始,每隔2行(即第1、3、5...行)# d:删除
2. 删除所有偶数行(保留奇数行)


5)增加
c a i

# 要使用 sed 在指定行下面添加一行,应该使用 a 命令[root@oldboyedu ~]# sed -i '/use_pty/a\Defaults editor=/usr/bin/vim, env_editor' /etc/sudoers# /符合匹配的行/ # 用来过滤# a # 在这个指定行后面追加内容# \ # 转义字符, 告诉 sed 后面紧跟的文本是命令的一部分, 命令没有结束sed '3a lidao996' 文件名# 后面这个lidao996是一个字符串, 中间隔着一个空格sed '$a 1234' 文件名# 在最后一行追加,1234 这里的$不是正则,表示最后一行的行数,是个数字sed -r '/正则/c lidao996' 文件名# / / 是一个地址范围(address), 用于匹配正则# c a i 是命令, 表示增加后面字符串这一行# 空格隔开, 后面紧跟字符串下面我们 c a i 前面跟的都是数字,其实他不止可以跟数字.还可以跟正则,

- 对于c a i来讲,-n选项可以加,也可以不加
- 为了全局可观看 一般不加-n



3c整行替换重点!
案例.免交互将selinux关闭
[root@oldboyedu ~]# sed -i '8c SELINUX=disabled' /etc/selinux/config# c 整行替换, 免交互关闭selinux
🧣w(保存到新文件)
- 保存到新文件中,如果没有将新建一个
- 如果有则覆盖里面的内容.
- 后面两次案例内容全部保存在1.txt中.
- 它也可以使用前面的正则. / / 包裹起来
- 也可以加**-r选项, 匹配扩展正则.**
- 通常配合-n使用,取消默认输出
- 注意引号位置,同时把文件名也包含在内!
- 这个新文件也可以使用绝对目录进行保存
案例.将第3行的内容保存到1.txt中
[root@oldboyedu ~]# sed -n '3w 1.txt' passwd.txt# w 后面跟保存到的文件名, 将第3行的内容保存到1.txt中
案例.将包含root或者sync的行,继续保存在1.txt中
[root@oldboyedu ~]# sed -rn '/root|sync/w 1.txt' passwd.txt# -r 扩展正则, w 保存到文件, 会覆盖之前的内容
在最后一行追加内容
在Linux中使用sed命令在文件er.txt最后一行追加内容1234,正确的命令是:
[root@oldboyedu ~]# sed '$a 1234' er.txt# $:表示最后一行# a 1234:在匹配行之后追加内容1234
其他解决方案:
直接用 echo ‘1234’ >> re.txt
直接追加到文件最后.
6)sed总结

- 下面这个是不含#的行,并不是 以#开头的行.

02.sort 排序
- sort 文件
- 其他命令 | sort
- 默认按照首个**字母(或者数字)进行排序.
- 默认升序排序,从小到大进行排序.
| 参数 | 说明 |
|---|---|
-n | 按照数值大小进行排序, 如果是数字必须加这个选项, 否则只会按照首个数字升序排 |
-r | 逆序排序(降序) |
-k | 指定列排序 |
案例.排序oldboy.txt 文件
[root@oldboyedu ~]# cat oldboy.txttestoldboyshelllinuxtabshazi[root@oldboyedu ~]# sort oldboy.txtlinuxoldboyshazishelltabtest# 默认按照首个字母进行排序, 升序案例.对数字的文件进行排序
[root@oldboyedu ~]# cat n.txt122010055008[root@oldboyedu ~]# sort n.txt110022055008# 按照首个数字大小进行排序(升序)'不加-n选项, 只会按首位数字排序, 所以1后面是100'案例.按照数字进行排序
[root@oldboyedu ~]# sort -n n.txt125820100500# 按数值的大小, 升序排'加了-n后, 就是真正的数值大小排序了'案例.按照数字的逆序排序
[root@oldboyedu ~]# sort -rn n.txt500100208521# 多了一个-r选项, 降序排📌 sort -rn 是 Linux 中用于按数值降序排序的强大命令组合.
案例.指定列进行排序 -k2 表示第2列
按照第2列的数字进行正序排序
- 升序,从小到大排
[root@oldboyedu ~]# sort -nk2 n.txtzs 1ls 2dd 8lw 20ed 90gs 100td 500# -k2 指定第2列, -n 数值升序案例.按照第二列的数字进行逆序排序
[root@oldboyedu ~]# sort -rnk2 n.txttd 500gs 100ed 90lw 20dd 8ls 2zs 1# 多加一个-r选项, 降序03.uniq 去重统计
- -c #去重并统计个数
- 将统计的个数,放在第一列
- 随机排序,并非升序
- 所以后面再继续跟sort -rn
- 按照数字的大小进行降序排序
- 即使只出现一次也会被统计出来.
⚠️ ①先排序②再去重
- 只能去紧挨着的重复的数据
- 如果不紧挨着,没有办法去重
- 所以我们要先进行排序
[root@oldboy home]# cat oldboy.txttestshelltestlinuxshelldocker[root@oldboy home]# cat oldboy.txt | uniqtestshelltestlinuxshelldocker# 直接去重,并没有成功,只能去紧挨着的重复的数据[root@oldboy home]# cat oldboy.txt | sortdockerlinuxshellshelltesttest# 排完后, 就紧挨着了[root@oldboy home]# cat oldboy.txt | sort | uniqdockerlinuxshelltest# 这次成功去重了案例.去重并统计个数
[root@oldboyedu ~]# cat oldboy.txt | sort | uniq -c 1 docker 1 linux 2 shell 2 test# 加上-c选项, 第一列显示出现次数# 出现一次也会统计案例.统计当前passwd.txt中每个单词出现的次数从大到小排序
- 先用sed 替换,把数字和特殊字符都换成空格
- 这个原理是把特殊字符啥的,都换成空格,
- 然后配合xargs -n1 把内容按照1列进行输出.

[root@oldboy home]# cat passwd.txt | sed -n 's#[0-9:/x]# #gp' | xargs -n1 | sort | uniq -c | sort -rn12 sbin6 nologin5 bin4 root3 var3 sync3 shutdown3 mail3 halt3 adm2 spool2 operator2 lp2 daemon1 lpd1 bash# 先把数字和特殊符号, 都替换为空格# 接着xargs -n1 排成一列输出# sort | uniq -c | sort -rn再来看一种方法:
- egrep 进行过滤完后, -o 把单词按照1列都过滤出来, 再跟 | sort | uniq -c |sort -rn
- ‘[a-Z]+’ #把连续的字母(单词)都过滤出来
- -o 的作用和 xargs -n 作用一样,变成一列输出.

我们也可以把这个单独的x去除掉


案例.对文件中任意字符进行统计、取出top10
[root@oldboy home]# grep -o '.' passwd.txt | sort | uniq -c | sort -rn | head60 :37 n35 /33 o26 i21 s18 b17 l17 a12 t# -o 输出过程, '.' 匹配任意字符# sort | uniq -c | sort -rn 统计并降序# head 取前10典型工作流示例
# 分析网站访问日志:统计IP访问量并排序[root@oldboy home]# awk '{print $1}' access.log | sort | uniq -c | sort -rn | head -10 1428 192.168.1.23 1205 10.0.0.45 983 172.16.5.201# ... (TOP 10 IPs)统计每一个字符(单词)出现的次数,并取出次数最多的前10位.

04.wc
📌 统计文件内容
🔹 默认输出(不加选项)
[root@oldboyedu ~]# wc file.txt 10 50 300 file.txt# 输出依次为:行数(lines) 单词数(words) 字节数(bytes) 文件名🔹 常用选项
| 选项 | 说明 |
|---|---|
-l | 只统计行数(lines) |
-w | 只统计单词数(words) |
-c | 只统计字节数(bytes) |
文章分享
如果这篇文章对你有帮助,欢迎分享给更多人!




