sed工具概述
Stream Editor,流式编辑器
- 非交互,基于模式匹配过滤及修改文本
- 逐行处理,并将结果输出到屏幕
- 可实现对文件的输出、删除、替换、复现、剪切、导入,导出等各种操作
命令格式解析
主要用法
格式1:前置命令 | sed [选项] ‘编辑指令’
举例:将单词首字母大写echo 'welcome to my home' | sed 's#\w#\u&#'

格式2:sed [选项] ‘编辑指令’ 文件…
举例:读取/proc/meminfo中的第1行sed -n '1p' /proc/meminfo
常用参数选项
| 选项 | 作用 | | —- | —- | | -n | 屏蔽默认输出 | | -i | 直接修改文件内容 | | -r | 启用扩展的正则表达式,若与其它选项一起使用应作为首个选项 | | -e | 可以指定多个处理动作 | | -f | 编辑动作保存在文件中,指定文件执行,此方式为sed脚本方式 | | -{} | 可能组合多个命令,以分号分隔 |
定址符
作用:
- 用来指定处理的起、止行数
- 省略定位符时,默认逐行处理全部文本
- 地址可表示为文本的”行号”,或者用来匹配的”/正则表达式/“ | 匹配模式 | 含义 | | —- | —- | | 10command | 匹配到第10行 | | 10,20command | 匹配从第10行开始,到第20行结束 | | 10,+5cmmand | 匹配从第10行开始,到第16行结束 | | /pattern1/command | 匹配到pattern1的行 | | /pattern1/,/pattern2/command | 匹配到pattern1的行开始,到匹配到pattern2的行结束 | | 10,/pattern1/command | 匹配从第10行开始,到匹配到pettern1的行结束 | | /pattern1/,10command | 匹配到pattern’的行开始,到第10行匹配结束 |
处理命令
命令列表
| 类别 | 动作 | 含义 |
|---|---|---|
| 查询 | p | 打印 |
| 增加 | a | 行后追加 |
| i | 行前追加 | |
| r | 外部文件读入,行后追加 | |
| w | 匹配行写入外部文件 | |
| 删除 | d | 删除 |
| 替换 | s/old/new/g | 将行内的old全部替换成new |
| s/old/new/2g | 将行内从第2个开始及以后old全部替换成new | |
| s/old/new/ig | 将行内的old全部替换成new,忽略大小写 |
拓展:
- 替换操作的分享
**"/"**可改用其它字符,如**#、&、!**,便于修改文件路径 打印操作使用
**=**可以输出行号,例如**sed -n '/^mail/{=;p}' /etc/passwd**基本使用
拷贝/etc/hosts文件测试,利用sed以下任务
1.删除文件 中每行的第二个、最后一个字符思路:第1次删掉第1个,第二次删掉第2个
sed 's#.##2;s#.$##' hosts

2.删除文件中每行的第二个、最后一个单词思路:分两次替换操作,第一次替换掉第2个单词,第二次替换掉最后一个单词
sed -r 's#[a-Z]+##2;s#[a-Z]+([^a-Z]*)$#\1#' hosts

3.将文件中每行的第一个、第二个字符互换方法:每行文本拆分为”第1个字符”、”第2个字符”、”剩下的所有字符”三个部分,然后通过替换操作重排顺序为”2-1-3”
sed -r 's;(.)(.)(.+);\2\1\3;' hosts

4.将文件中每行的第一个、第二个单词互换方法:每行文本拆分为”第1个单词”、”单词分隔”、”第2个单词”、”剩下的所有字符”四个部分,然后通过替换操作重排顺序为”3-2-1-4”
sed -r 's#([a-Z]+)([^a-Z]*)([a-Z]+)(.*)#\3\2\1\4#' hosts

5.删除文件中所有的数字、行首的空格方法:分两次替换,第1次替换数字,第2次替换空格

6.为文件中每个小写字母添加括号
- 方法:使用”&”可调用s替换操作中的整个查找串

7.编辑一个sed脚本
- 将所有单词首字母大写
- 将所有空行删掉
- 在每一行后面添加换行
1.脚本内容
s;([a-Z]+)([^a-Z]*);\u\1\2;g/^$/d/[^\S]/a\\
2.运行脚本
sed -r -f script.sed hosts
shell中变量的引用
1.匹配模式中存在变量,则建议使用双引号
sed "s/$old_str/$new_str"
2.sed中需要引入自定义变量时,如果外面使用单引号,则自定义变量也必须使用单引号
sed 's/'$old_str'/'$new_str''
反向引用
&和\1:引用模式匹配到的整个串
例1:使用**&**给/etc/passwd中的以r开头t结尾的4字母单词添加上括号
sed 's/r..t/[&]/g' /etc/passwd |head -1

例2:使用**\1**给/etc/passwd中的以r开头t结尾的4字母单词添加上括号
sed -r 's/(r..t)/<*\1*>/g' /etc/passwd |head -1

上面两种方式实现了一样的功能,分别使用&和\1引用前面匹配到的字符串
两者区别在于:
&匹配到的是完整的字符串,只能引用整个字符串\1可以使用()对匹配的字符进行引用
例如:如果我们仅想替换匹配到的字符串的一部分,则必须使用\1这种方式。
需求:现在想把sshd_config文件中的允许root登录改成不允许root登录
这里使用正则的反向引用来完成,将yes改成no
查询用法
命令对照表
| 命令 | 功能 |
|---|---|
| 1p | 打印第1行内容 |
| 1,10p | 打印1行到10行的内容 |
| 1,+5p | 打印1行到6行的内容 |
| /pattern1/p | 打印每行中匹配到pattern1的行内容 |
| /pattern1/,/pattern2/p | 打印匹配到pattern1的行直到匹配到pattern2的所有行内容 |
| /pattern1/,10p | 打印匹配到pattern1的行到10行的所有行内容 |
| 10,/pattern1/p | 打印第10行直到匹配到pattern1的所有行内容 |
练习举例
1.打印/etc/passwd中第20行的内容
sed -n '20p' /etc/passwd

2.打印/etc/passwd从第6行开始,到第15行结束的内容
sed -n '8,15p' /etc/passwd

3.打印/etc/passwd从第18行开始,然后+3行结束的内容
4.打印/etc/passwd中以内容为**sys**开头的行
5.打印/etc/passwd中以root开始的行,到开头为**sys**的行结束
6.打印/etc/passwd从24行开始,到行结尾含有**nologin**的内容结束
7.打印/etc/passwd中第一个以**bash**结尾的字符串开始,到第5行结束
注意了:
- 这里找到以bash结尾字符串的行是在第38行,我们给的条件是第5行结束
- 这里输出的结果只要38一行,所以得出结论,找到的行 > 结束行,那么结束的行就等于找到的行
其它补充
| 示例 | 含义解析 | | —- | —- | | sed -n ‘p’ msg.txt | 输出所有行,等同于cat msg.txt | | sed -n ‘4p’ msg.txt | 输出第4行 | | sed -n ‘4,7p msg.txt | 输出第4~7行 | | sed -n ‘4,+10p’ msg.txt | 输出第4行及其后的10行内容 | | sed -n ‘/^bin/p’ msg.txt | 输出以bin开头的行 | | sed -n ‘p;n’ msg.txt | 输出奇数行,n表示读入下一行文本(隔行) | | sed −n’n;p’ msg.txt | 输出偶数行,n表示读入下一行文本(隔行) | | sed -n ‘10,${n;p}’ msg.txt | 输出从第10行至文件末尾的所有偶数行 | | sed −n’$=’ msg.txt | 输出文件的行数 |
删除内容
命令对照表
| 查询命令 | 含义 |
|---|---|
| 1d | 删除第1行内容 |
| 1,10d | 删除1行到10行的内容 |
| 1,+5d | 删除1行到6行的内容 |
| /pattern1/d | 删除每行中匹配到pattern1的行内容 |
| /pattern1/,/pattern2/d | 删除匹配到pattern1的行直到匹配到pattern2的所有行内容 |
| /pattern1/,10d | 删除匹配到pattern1的行到10行的所有行内容 |
| 10,/pattern1/d | 删除第10行直到匹配到pattern1的所有行内容 |
练习举例
1.删除/etc/passwd中第1行
sed '1d' /etc/passwd
2.删除/etc/passwd中第6,21行的所有内容
sed '6,21d' /etc/passwd
3.删除/etc/passwd中不是以bash或zsh内容结尾的用户
sed -r '/bash$|zsh$/!d' /etc/passwd

4.删除/etc/passwd中以sys开头到以mail开头的行的所有内容
sed '/^mail/,/^system/d' /etc/passwd

5.删除/etc/passwd中第1个不能登录的用户,直到15行的所有内容
sed -r '/nologin|false/,15d' /etc/passwd

注意:
- 这个输出的结果和我们想的有差距,nick是在/etc/passwd文件中的最后一行
- 但是我们的条件是直到15行为止,它并没有到了15行就结束而是继续往下匹配
- 所以在实际的运用中不推荐这种方式,推荐下面这种数字在前表达式在后的方式
6.删除/etc/passwd中第3行到以sshd开头的所有行内容
sed '3,/^sshd/d' /etc/passwd

7.删除/etc/passwd中以nobody开头的行到结尾行所有的内容
sed '/^mail/,/$$/d' /etc/passwd

8.删除/etc/passwd中不能登录的所有用户
sed -r '/nologin|false$/d' /etc/passwd
其它补充
| 命令 | 功能 |
|---|---|
| sed ‘1,3n’ myfile | 删除第3-5行 |
| sed ‘/html/d’ myfile | 删除所有包含html的行 |
| sed ‘/html/!d’ myfile | 不删除所有包含html的行 |
| sed ‘/^#/d’ myfile | 删除以#号开头的行 |
| sed ‘$d’ myfile | 删除最后一行 |
| sed ‘/^$/d’ myfile | 删除所有的空行 |
| sed ‘/^$/{n;/^$/d}’ myfile | 删除重复空行,连续两个空行只保留一个 |
替换用法
命令对照表
| 编辑命令 | 含义 |
|---|---|
| 1s/old/new/ | 替换第1行内容old为new |
| 1,10s/old/new/ | 替换1行到10行的内容old为new |
| 1,+5s/old/new/ | 替换1行到6行的内容old为new |
| /pattern1/s/old/new/ | 替换匹配到pattern1的行内容old为new |
| /pattern1/,/pattern2/s/old/new/ | 替换匹配到pattern1的行直到匹配到pattern2的所有行内容old为new |
| /pattern1/,10s/old/new/ | 替换匹配到pattern1的行到10行的所有行内容old为new |
| 10,/pattern1/s/oId/new/ | 替换第10行直到匹配到pattern1的所有行内容old为new |
练习举例
s/old/new
1.在行尾添内容
echo "hahalalayayaxixi" | sed "s/$/-wawawawaw/"
2.将所有的小写字母转成大写(**\u**是把下一个字符转成大写upper)
echo "hello everyone" | sed 's/[a-z]/\u&/g'
3.将所有的大写转换成小写(**\l**是把下一个字符转成小写lower)
echo "HELLO SHENQI"| sed 's/[A-Z]/\l&/g'
1s/old/new/1
1.将第一行第一个小写字符替换成大写字符
echo "how are your yayayay\~\~\~" |sed '1s/[a-z]/\\u&/1'
3,6,s/old/new/2
1.将.bashrc文件中第3行到第5行的第二个空格替换成*** * ***
sed '3,6s/ /***/2' ~/.bashrc
2,+4s/old/new/3
1.将/etc/passwd文件中,从第2行开始往后数4行的第3个字母,用**()**括起来
sed '2,+4s/[A-Za-z]/(&)/3' /etc/passwd|head
/pattern1/s/old/new/3gp
1.匹配/etc/passwd文件中以字母或者数字开头的行,并且长度大于等于10,并把它们第3位数字及以后的数字加上**()**
sed -rn '/^[a-zA-Z0-9]{10,}/s/[0-9]/(&)/3gp' /etc/passwd
/pattern1/,/pattern2/s/old/new/g
1.匹配所有的if代码块,将里面的.替换成source
sed -rn '/^if/,/^fi/s/ {1,}+\./source/p' ~/.bashrc
15,/pattern1/s/old/new/ig
1.从第15行开始匹配/etc/passwd文件中结尾是**/usr/sbin/nologin**的行并将它们全部替换成**/bin/false**
sed -rn -e '15,/.+/{=;s#/usr/sbin/nologin$#/bin/false#p}' /etc/passwd
其它补充
| 示例 | 含义解析 |
|---|---|
| sed ‘s/html/HTML/‘ tmp.txt | 将每行中第一个html替换为HTML |
| sed ‘s/html/HTML/3’ tmp.txt | 将每行中的第3个html替换为HTML |
| sed ‘s/html/HTML/g’ tmp.txt | 将所有的html都替换为HTML |
| sed ‘s/html//g’ tmp.txt | 将所有的html都删除(替换的空串) |
| sed ‘s/doc/&s/g’ tmp.txt | 将所有的doc都替换为docs,&代表匹配到的串 |
| sed ‘3,9s/^/#/‘ tmp.txt | 将第3~9行注释掉(行首加#号) |
| sed ‘s/^#sys/sys/‘ tmp.txt | 解除以#sys开头的行的注释(去除行首的#号) |
追加用法
| 命令 | 作用 |
|---|---|
| a | 在匹配行后面追加内容 |
| i | 在匹配行前追加内容 |
| c | 替换当前行 |
a—append
1.复制passwd文件到家目录,在文件中第1,10行追加system user
cp /etc/passwd ~/sed -i '1,10asystemuser' ~/passwd

2.在passwd文件中将所有以bash或zsh结尾的用户后追加login user
sed -r '/(bash|zsh)$/a login user' ~/passwd
i—insert
1.将uname -a 的结果,插入到/etc/issue第1行。
kernel=`uname –a`sed -i "1i$kernel" /etc/issue
2.将echo $USER login 插入到家目录下的.bashrc文件中第1行
sed -i '1iecho $USER login' \~/.bashrc
c—change
1.将sshd_config配置文件中PermitRootLogin设置成yes
sed -ri '/#PermitRootLogin/c PermitRootLogin yes' /etc/ssh/sshd_config
导入导出
基本动作
- r 动作应结合-i选项才会存入,否则只输出
- w 动作以覆盖的方式另存为新文件 | 命令 | 作用 | | —- | —- | | r | 将文件内容追加到匹配行后面 | | w | 将匹配行写入指定文件 |
r—read
1.
- 读取/etc/fstab放到标准输出的第一行后面
此方法也是在文件中开头与结尾添加内容最快的方法
echo -e "#这是开机分区挂载文件\n#以上就是分区内容" |sed '1r /etc/fstab'

2.读取welcome.php文件中的内容,放到index.php的<?php到最后一行之间sed '/<?php/r welcome.php' index.php
welcome.php文件内容
echo "<h1>这是我的第一个网页</h1>";
index.php文件内容
<?phpphpinfo();?>
w-write
1.匹配/etc/passwd以bash或zsh结尾的行,写到
**login_ok**文件中sed -rn '/(bash|zsh)$/w login_ok' /etc/passwd

2.将/var/log/auth.log从第1行开始往后数9行放到**top10.msg**文件中sed -n '1,+9w top10.msg' /var/log/messages
复制剪切
模式空间
存放当前处理的行,将处理结果输出
- 若当前行不符合处理条件,则原样输
-
保持空间
作用类似于”剪贴板”
-
基本动作
H:模式空间——【追加】——>保持空间
- h:模式空间——【覆盖】——>保持空间
- G:保持空间——【追加】——>模式空间
- g:保持空间——【覆盖】——>模式空间
- 小结:H/h——>复制,G/g——>粘贴
复制示例
1.将/etc/passwd前9行内容写到/tmp/pass文件中
2.将1到3行复现到文件结尾head -9 /etc/passwd > /tmp/pass
sed '1,3H;$G' /tmp/pass

命令执行后发现图中方框内存在一个空行,是因为保持空间里面默认就是一个空行
3.改用下列方式可避免出现空行
# 原理就是将第1行覆盖到保持空间sed '1h;2,3H;$G' /tmp/pass
剪贴示例
1.将文件前3行剪切到文件结尾
sed '1h;2,3H;1,3d;$G' /tmp/pass
sed流控制
!取反操作
用途:
- 根据定址条件取反
示例
- 列出shell环境不是
nologin和false的用户账号记录
n读下一行
用途
- 读入下一行进行处理(产生隔行/跳行的效果)
示例
- 分别列出文件的奇数/偶数行
1.输出奇数行
2.输出偶数行
