Linux sed
Stream EDitor,流式编辑器
- 非交互,基于模式匹配过虑及修改文件
- 逐行处理,并将结果输出到屏幕
- 可实例对文本的输出、删除、替换、复制、剪切、导入、导出等各种操作
一、基本正则列表与扩展正则
根据推出时间的不同,分为基本正则和扩展正则,扩展正则在基本正则的基础上做了一些优化和新增了一些正则表达符号,因为一些命令没有及时更新,所以你可能会遇到有些命令只支持基本正则,不支持扩展正则,或者需要添加一些支持扩展正则的选项。
关于正则与扩展正则区别的详细介绍可以看我另一篇shell 正则的介绍
二、sed 文本处理工具的用法介绍:
- 用法1:前置命令 | sed [选项]'条件指令'
- 用法2:sed [选项]'条件指令' 文件....
相关说明如下:
- 条件可以是行号或者/正则/
- 没有条件时,默认为所有条件
- 指令可以是增、删、改、查等指令
- 默认sed会将所有输出的内容都打印出来,可以使用-n屏蔽默认输出
- 选项中可以使用-r选项,让sed支持扩展正则
sed命令的常用选项如下:
- -n 屏蔽默认输出,默认sed会输出读取文档的全部内容
- -r 让sed支持扩展正则 若与其它选项一起使用,应放作为首选项
- -i sed直接修改源文件,默认sed只是通过内存临时修改文件,源文件无影响
- -e 多点编辑 让一条sed可以执行多条指令
sed命令常用条件指令如下
- d:删除指定的字符
- p:显示指定的行
- s:替换指定的字符
- i: 在指定的行之前插入文本
- a:在指定的行之后追加文本
- c:替换指定的行
- r:读取文件
- w:保存到文件
三、认识sed工具的 n、r、i 选项指令
\# sed [选项] '条件指令' 文件.. ..
上面的条件指令 我们可以拆分为 # sed [选项] '范围界定+操作指令' 文件.. .. 的格式这样更容易理解
sed -n '/bash$/ s/:.*//p' /etc/passwd // 选项 -n 范围界定/bash$/ + 操作指令s/:.*//p
sed命令可以使用行号或正则做为条件匹配:
1)sed命令的 -n 选项
执行p打印等过滤操作时,希望看到的是符合条件的文本。但不使用任何选项时,默认会将原始文本一并输出,从而干扰过滤效果。比如,尝试用sed输出/etc/hosts的第1行:
[root@server ~]# sed '1p'/etc/hosts
127.0.0.1 localhost localhost.localdomain localhost4 localhost4.localdomain4
127.0.0.1 localhost localhost.localdomain localhost4 localhost4.localdomain4
::1 localhost localhost.localdomain localhost6 localhost6.localdomain6
可以发现所有的行都被显示出来了(第1行重复2次)。—— 正确的用法应该添加 -n 选项,这样就可以只显示第1行了:
[root@server ~]# sed -n '1p'/etc/hosts
127.0.0.1 localhost localhost.localdomain localhost4 localhost4.localdomain4
行号可以是连续的行号,如打印passwd第3到第6行账户的信息:
[root@server ~]# sed -n '3,6p'/etc/passwd
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
2)sed命令的 -r 选项
需要用到扩展正则时,需要加 -r选项
[root@server ~]# sed -r 's/bash|nologin/xxxx/g' '/etc/passwd //把所有bash或nologin替换为xxxx
3)sed命令的 -i 选项
正常情况下,sed命令所做的处理只是把操作结果(包括打印、删除等)输出到当前终端屏幕,而并不会对原始文件做任何更改:
[root@server ~]# sed 'd'/etc/passwd //删除所有行
[root@server ~]# cat /etc/passwd //查看原始文本,并未改动
若希望直接修改文件内容,应添加选项 -i 。
需要特别注意的是,和一些指令组合和使用的先后顺序都会对最终输出结果产生影响
例如: 指令 -n、和操作操作p
[root@server ~]# sed -in 's/2017/xxx/' test.txt // n在i后面不影响结果
[root@server ~]# cat test.txt
xxx20112018
xxx20172024
xxx20172017
[root@server ~]# sed -ni 's/2017/xxx/' test.txt // n在i前面 因为n已经屏蔽了所有显示 所以结果为空
[root@server ~]# cat test.txt
[root@server ~r]# sed -in 's/2018$/xxx/p' test.txt // n在i后面不影响结果 但P后面的显示指令 让匹配项重复显示行写入到了文件
[root@server ~]# cat test.txt
20172011xxx
20172011xxx
201720172024
201720172017
[root@server ~]# sed -ni 's/2018$/xxx/p' test.txt # n在i前面 后面 P指令只把匹配项写入了文件
[root@server ~]# cat test.txt
20172011xxx
比如,直接删除test.txt(自行创建一个任意内容的文件)的第1~4行:
[root@server ~]# sed -i '1,4d' test.txt //删除操作
[root@server ~]# cat test.txt //确认删除结果
下文中关于使用sed修改文件的示例中,为了避免大家在练习过程中因误操作导致系统故障,命令省略 –i 选项,不再逐一说明。需要时,大家可自行加上此选项。
4)多个指令可以使用分号隔离
用分号来隔离多个操作,比如:
[root@server ~]# sed -n '1p;4p'/etc/passwd
root:x:0:0:root:/root:/bin/bash
adm:x:3:4:adm:/var/adm:/sbin/nologin
1)行号案例
打印第3行:
[root@server ~]# sed -n '3p'/etc/passwd
打印第3到5行:
[root@server ~]# sed -n '3,5p'/etc/passwd
打印第3和5行:
[root@server ~]# sed -n '3p;5p'/etc/passwd
打印第3以及后面的10行:
[root@server ~]# sed -n '3,+10p'/etc/passwd
打印奇数行:
[root@server ~]# sed -n '1~2p'/etc/passwd
打印偶数行:
[root@server ~]# sed -n '2~2p'/etc/passwd
2)正则案例
打印包含root的行:
[root@server ~]# sed -n '/root/p'/etc/passwd
打印bash结尾的行:
[root@server ~]# sed -n '/bash$/p'/etc/passwd
3)没有条件,则表示匹配所有行
[root@server ~]# sed -n 'p'/etc/passwd
四、认识sed工具的 p、d、s 条件指令
1)下面看看sed工具的p指令案例集锦(自己提前生成一个a.txt文件)
[root@server ~]# sed -n 'p' a.txt //输出所有行,等同于cat a.txt
[root@server ~]# sed -n '4p' a.txt //输出第4行
[root@server ~]# sed -n '4,7p' a.txt //输出第4~7行
[root@server ~]# sed -n '4,+10p' a.txt //输出第4行及其后的10行内容
[root@server ~]# sed -n '/^bin/p' a.txt //输出以bin开头的行
[root@server ~]# sed -n '$=' a.txt //输出文件的行数
2)下面看看sed工具的d指令案例集锦(自己提前生成一个a.txt文件)
[root@server ~]# sed '3,5d' a.txt //删除第3~5行
[root@server ~]# sed '/xml/d' a.txt //删除所有包含xml的行
[root@server ~]# sed '/xml/!d' a.txt //删除不包含xml的行,**!符号表示取反**
[root@server ~]# sed '/^install/d' a.txt //删除以install开头的行
[root@server ~]# sed '$d' a.txt //删除文件的最后一行
[root@server ~]# sed '/^$/d' a.txt //删除所有空行
3)sed命令的s替换基本功能(s/旧内容/新内容/选项):
[root@svr5 ~]# vim test.txt //新建素材
201720112018
201720172024
201720172017
[root@server ~]# sed 's/2017/xxxx/' test.txt //将每行中第一个2017替换为xxxx
[root@server ~]# sed 's/2017/xxxx/g' test.txt //将每行中所有2017替换为xxxx
[root@server ~]# sed 's/2017/xxxx/2' test.txt //将每行中第2个2017替换为xxxx
[root@server ~]# sed 's/2017//2' test.txt //将每行中第2个2017删除
[root@server ~]# sed -n 's/2017/xxxx/p' test.txt //将每行中第一个2017替换为xxxx 并显示
4)下面看看sed工具的s指令案例集锦(自己提前生成一个a.txt文件)
注意:替换操作的分隔“/”可改用其他字符,如#、&等,便于修改文件路径
[root@server ~]# sed 's/xml/XML/' a.txt //将每行中第一个xml替换为XML
[root@server ~]# sed 's/xml/XML/3' a.txt //将每行中的第3个xml替换为XML
[root@server ~]# sed 's/xml/XML/g' a.txt //将所有的xml都替换为XML
[root@server ~]# sed 's/xml//g' a.txt //将所有的xml都删除(替换为空串)
[root@server ~]# sed 's#/bin/bash#/sbin/sh#' a.txt //将/bin/bash替换为/sbin/sh
[root@server ~]# sed '4,7s/^/#/' a.txt //将第4~7行注释掉(行首加#号)
[root@server ~]# sed 's/^#an/an/' a.txt //解除以#an开头的行的注释(去除行首的#号)
以下操作使用nssw.txt作为测试文件。
参考数据文件内容如下:
[root@server ~]# cat nssw.txt
Hello the world
ni hao ma beijing
5)删除文件中每行的第二个、最后一个字符
分两次替换操作,第一次替换掉第2个字符,第二次替换掉最后一个字符:
[root@server ~]# sed 's/.//2 ; s/.$//' nssw.txt
6)将文件中每行的第一个、倒数第1个字符互换
每行文本拆分为“第1个字符”、“中间的所有字符”、“倒数第1个字符”三个部分,然后通过替换操作重排顺序为“3-2-1”:
[root@server~]# sed -r 's/^(.)(.*)(.)$/\3\2\1/' nssw.txt
7)删除文件中所有的数字
因原文件内没有数字,行首也没有空格,这里在内容中新增一些数字另外新几行内容 首行添加几行空格,生成一个新测试文件以 nssw2.txt
[root@server ~]# sed 's/[0-9]//' nssw.txt //无效因为里面不包含数字
以nssw2.txt文件为例,删除所有数字、行首空格的操作如下:
[root@server ~]# sed -r 's/[0-9]//g;s/^( )+//' nssw2.txt
8)为文件中每个大写字母添加括号[]
使用“()”可实现保留功能,所以可参考下列操作解决:
[root@server ~]# sed -r 's/([A-Z])/[\1]/g' nssw.txt
五、认识sed工具的 i、a、c 条件指令
\# sed [选项] '条件指令' 文件..
sed工具的多行文本处理操作:
- i: 在指定的行之前插入文本
- a:在指定的行之后追加文本
- c:替换指定的行
基本语法格式案例:
[root@server ~]# sed '2a XX' a.txt //在第二行后面,追加XX
[root@server ~]# sed '2i XX' a.txt //在第二行前面,插入XX
[root@server ~]# sed '2c XX' a.txt //将第二行替换为XX
1)sed命令的 i 指定行之前插入基本功能
[root@server ~]# sed '2i xxxx' nssw.txt //将第二行前插入xxxx
[root@server ~]# sed 'c xxxx' nssw.txt //在所有行前插入xxxx
2)sed命令的a追加基本功能
[root@server ~]# sed '3a xxxx' nssw.txt //将第三行后追加xxxx
[root@server ~]# sed 'a xxxx' nssw.txt //在所有行后追加xxxx
3)sed命令的c替换基本功能
[root@server ~]# sed '1c xxxx' nssw.txt //将第一行替换为xxxx
[root@server ~]# sed 'c xxxx' nssw.txt //对所有行替换成xxx
[root@server ~]# sed '1,3c xxxx' nssw.txt //对1到3行替换成xxx
六、认识sed高级应用 r、w 条件指令
新建文件 a.txt n.txt
[root@server sed]# cat a.txt
aabbccdd
eeffgghh
iijjkkll
[root@server sed]# cat n.txt
11223344
55667788
99001122
1)sed命令的 r 读取文件
[root@server sed]# sed '2r a.txt' n.txt \\在第2行插入a.txt
11223344
55667788
aabbccdd
eeffgghh
iijjkkll
99001122
[root@server sed]# sed '/^ee/r n.txt' a.txt \\在以ee开头的行下方插入n.txt
aabbccdd
eeffgghh
11223344
55667788
99001122
iijjkkll
[root@server sed]# sed '1,3r n.txt' a.txt \\在以1到3行下方分别插入n.txt
2)sed命令的 w 保存到文件
[root@server sed]# sed -n '1,3w c.txt' a.txt \\把1到3主存储为新文件c.txt
[root@server sed]# cat c.txt
aabbccdd
eeffgghh
iijjkkll
[root@server sed]# sed -n '/^ii/w d.txt' a.txt \\把ii开头的行保存为d.txt
[root@server sed]# cat d.txt
iijjkkll
七、综合案例
1) 综合案例1
[root@server sed]# cp /etc/passwd .
[root@server sed]# nl /etc/passwd | sed '2,5d' // **删除2到5行 | 管道后使用 -i 选项无效**
[root@server sed]# nl passwd | sed '3,$d' //删除3到最后一行
[root@server sed]# nl passwd | sed '2i hostfile' > passwd.new //在第2行前插入''hostfile'' 并生成新文件 passwd.new
[root@server sed]# nl passwd | sed -n '/root/p' //显示包含root的行
[root@server sed]# nl /etc/passwd | sed '/root/{s/bash/black/;p;q}' //花括号中的一组命令,每个命令之间用分号分隔,找到root的行把bash替换成clack p输出显示 q是退出
[root@server sed]# ifconfig eth0 | grep 'inet'|sed 's/inet\s//g'|sed 's/\snetmask.*$//g' \\获取本机的IP地址 其中\s 表示匹配空格
[root@server sed]# sed -e '3,$d' -e 's/bash/blueshell/' passwd // 多点编辑 一条sed命令,删除/etc/passwd第三行到末尾的数据,并把bash替换为blueshell
root:x:0:0:root:/root:/bin/blueshell
bin:x:1:1:bin:/bin:/sbin/nologin
2)综合案例2 脚本应用
- 本案例要求编写脚本getupwd.sh,实现以下需求:
找到使用bash作登录Shell的本地用户
列出这些用户的shadow密码记录
按每行“用户名 --> 密码记录”保存到getupwd.log - 基本思路如下:
先用sed工具取出登录Shell为/bin/bash的用户记录,保存为临时文件/tmp/urec.tmp,并计算记录数量
再结合while循环遍历取得的账号记录,逐行进行处理
针对每一行用户记录,采用掐头去尾的方式获得用户名、密码字串
按照指定格式追加到/tmp/getuupwd.log文件
结束循环后删除临时文件,报告分析结果 脚本的编写
步骤一:编写getupwd.sh脚本[root@server sed]# cat getupwd.sh #!/bin/bash A=$(sed -n '/bash$/ s/:.*//p' /etc/passwd) ##提取符合条件的帐号记录 for i in $A ##遍历帐号记录 do pass1=$(grep $i /etc/shadow) ##搜索对应帐号shadow中的行 pass2=${pass1#*:} pass=${pass2%%:*} ##截取密码 echo "$i -->$pass" done [root@server sed]# ./getupwd.sh root -->$6$SAyc777Q$DgGi7Pnln0or.Ds04oyL6Y.QnVlMgZDRHMKKICJhiUAHBy4lvziPAZoW0MJz81xYonskLozvzhvNa4H59ngSl1 nginx -->!! bigyong -->!! kaka5 -->$6$uyZDpbUl$.CjkBefPZHXrRTcKc1csv7ZbbhHMMD4oQmum9lajJ1ot9at6fmIey5AE4kmUSoaWE/ofmFxyP2Dc6PAcczXdw0 harry -->!!