流编辑器 sed
Posted 我一个月改一次名
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了流编辑器 sed相关的知识,希望对你有一定的参考价值。
目录
前言
如果想在 shell 脚本中处理任何类型的数据,需要熟悉Linux中的 sed 和 gawk 工具,这两个工具能够极大简化需要进行的数据处理任务。
没学习sed 之前我们对文件 新增 处理 删除行都是通过执行 vim 命令 在编辑器中操作的,现在我们可以用sed来直接通过命令进行处理。
一、sed 编辑器
概念:
sed 编辑器 是一种 流编辑器,流编辑器会在编辑器处理数据之前基于预先提供的一组规则来编辑数据流。
sed 编辑器可以根据命令来处理数据流中的数据,这些命令要么从命令行中输入,要么存储在一个命令文本文件中。
sed 流编辑器 读取是 从上往下一行一行读的。
1.1 sed 的工作流程
sed 的工作流程主要包括 读取、执行 和 显示 三个过程:
- 【读取】:sed 从 stdin 输入流(文件、管道、标准输入)中 读取一行内容 并 存储到临时的缓冲区中(又称模式空间,pattern space),从上到下,按行读取。
- 【执行】:默认情况下,所有的 sed 命令都在模式空间中顺序地执行(从上往下),除非指定了行的地址,否则 sed 命令 将会在所有的行上依次执行。
- 【显示】:发送修改后的内容到输出流。在发送数据后,模式空间(缓冲区)将会被清空。
- 在所有的文件内容都被处理完成之前,上述过程将重复执行,直至所有内容被处理完。
注意:默认情况下所有的 sed命令都是在模式空间(缓冲区)内执行的,因此输入的文件内容并不会发生任何变化,除非使用重定向 > 存储输出。
1.2 sed 命令格式
格式一:
sed [选项] '操作' 文件1 [文件2] ...
如:
sed -n -e 'p' filename1.txt #打印输出文件内容一次
格式二:
sed [选项] '选项{
操作1
操作2
...
}' 文件1 [文件2] ...
如
sed -n '
=
p
' sedfile.txt
如:
sed -e '操作' 文件1 文件2 ... #执行操作命令
sed -n -e '操作'文件1 文件2 ... #执行操作命令,不产生输出
sed -i -e '操作'文件1 文件2 ... #直接修改目标文本文件
sed -f 脚本文件 文件1 文件2 ... #处理文件
常用选项:
选项 | 说明 |
---|---|
-e | (默认选项)-e 脚本 :表示用指定命令来处理输入的文本文件,只有一个操作命令时可省略,一般在执行多个操作命令使用 |
-f | -f 脚本文件file :表示用指定的脚本文件来处理输入的文本文件(添加到程序的运行列表) |
-h | 显示帮助 |
-n 或 silent | 禁止sed编辑器输出(不产生输出),但可以与 p、print 命令来完成输出 |
-i | 直接修改目标文本文件 |
-r | 使用扩展正则表达式(表达式要用写在 // 符号中进行解释) |
注:操作真实文件内容前记得备份!备份!备份!
常用操作:
【键盘】 【功能】
=: 打印行号。
s: 替换,替换指定字符。
d: 删除,删除选定的行。
a: 增加,在当前行下面增加一行指定内容。
i: 插入,在选定行上面插入一行指定内容。
c: 替换,将选定行替换为指定内容。
y: 字符转换,转换前后的字符长度必须相同。
q: 退出
n: 跳到下一行
r: 跟文件名,注入文件中的内容
p: 打印
#如果同时指定行,表示打印指定行,如5p 1,3p(打印一到三行) 10, $p(打印末行);
#如果不指定行,则表示打印所有内容;如果有非打印字符,则以 ASCII 码输出。其通常与“-n”选项一起使用。
l(小写L):打印数据流中的文本和【不可打印的】ASCII字符(比如结束符$、制表符\\t)
多个操作用分号 ; 隔开,执行顺序从左到右。
用 sed 操作文件
注:
- 使用 -n 后,再使用 ‘p’ ‘=’ 等操作,操作符默认已经加上了 -e 选项,如果写出来的话,-e 要写在 -n 后面;
1.3 查找、输出
p 操作
打印内容
1.3.1 显示一个文件内容
-e 会输出一遍文件内容, p 操作又会输出一遍,所以重复了;用 -n 选项解决这个问题。
1.3.2 显示文件内容和行号
sed '=' sedfile.txt #行号在内容上面
等同于
sed -n -e '=;p' sedfile.txt #先追加行号再打印
; 表示先后顺序
#先打印内容,再输出行号
sed -n -e 'p' -n -e '=' sedfile.txt
#扩展:输出内容并展示不可打印字符
sed -n -e 'l' sedfile.txt
1.3.3 使用寻找地址功能
sed 编辑器有两种寻址方式:
- 以数字形式表示行区间
- 用文本模式来过滤出行
- 注:数字与文本都要写在操作符的左边,文本需要用
//
解释
1 . 以数字形式表示行区间
n 表示跳到下一行
行的范围 与操作符一起使用后,操作符需要加在 ${}
中
2 . 用文本模式来过滤出行
- 文本需要写在 // 中,
/文本/操作符
- 区分大小写
- | 等符号需要加转义符 \\
sed -n -e '/root/p' /etc/passwd
sed -n -e '/bash$/p' /etc/passwd
sed -n -e '/ftp\\|root/p' /etc/passwd
使用 -r
选项表示 操作中支持使用正则表达式,表达式要用 //
符号进行解释。
#正则表达式表示打印 以ro开头,o至少出现一次的字符串所在的行
sed -n -r '/ro{1,}t/p' /etc/passwd
1.4 删除
- sed 是把文件读取到缓冲区中,在缓冲区中进行的删除,并不修改原文件的内容
- 删除
操作符d
不能与-n
选项一起使用,不然什么都不会输出
sed 'd' sedfile.txt #全删
sed '3d' sedfile.txt #删除第三行
'3,6d' 删3到6行 '3,$d' 删三到末尾所有行
sed -r '/^$/d' sedfile.txt #使用正则表达式 删除空行
删除空行另外两种方法:
cat sedfile.txt | tr -s '\\n'
cat sedfile.txt | grep -v "^$"
sed -r '/nologin$/d' /etc/passwd
sed -r '/nologin$/!d' /etc/passwd #!取反操作
#删除从。。到。。。之间的行,继续往下找,指直到文件读取完
sed '/1/,/3/d' numsedfile.txt
1.5 替换(常用)
格式:行范围 s/旧字符串/新字符串/替换标记
- 行范围 与后面用空格隔开
- 行范围如果是正则表达式,用 // 解释
4种替换标记:
数字:表明新字符串将替换【第几处匹配的地方】
g:表明新字符串将会替换【所有匹配的地方】
p:打印与替换命令匹配的行,与 -n 一起使用
w 文件:将替换的结果写到文件中
行范围可以用 1,4 或 1+3 等表示
1 . 直接替换
sed -n -e 's/root//gp' /etc/passwd #将所有的(g) root 替换成空
sed -n -e 's/root//p' /etc/passwd #将第一个 root 替换成空
sed -n -e 's/root//2p' /etc/passwd #将第二个 root 替换成空
#将文件 /etc/passwd 第1到20行的 开头替换成#号
sed '1,20 s/^/#/' /etc/passwd
#将root开头的行 结尾替换为#
sed '/^root/ s/$/#/' /etc/passwd
#替换标记为空
2 . 使用指定的脚本文件来处理输入的文本文件
格式 : -f 脚本文件file
其实就是把多条 sed 操作语句放到文件中,这样能够一次执行多条语句,不然只能一条一条的执行下去。
测试:
新增文件 script.sed ,添加内容:
/^root/ s/^/#/
/bash$/ s/\\/bin\\/bash/\\/sbin\\/nologin/
#//之间的符号要使用转义符
执行:
能够根据scripr.sed文件中的语句对 /etc/passwd 进行多次操作。
3 . 把 sed 执行结果写到文件中
#把 /etc/passwd 中第1到5行写到文件out.txt 中
sed '1,5w out.txt' /etc/passwd
#把 /etc/passwd 中第1到5行,的开头加上# 后 写到文件out.txt 中
sed '1,5 s/^/#/w out.txt' /etc/passwd
4 . 修改字符串分隔符
修改分隔符的好处是不需要再给表达式的重名如 / 再加上转义符\\了。
#把/bin/bash 替换为 /bin/csh
sed -n 's/\\/bin\\/bash/\\/bin\\/csh/p' /etc/passwd
#用!作为替换的分隔符,等同于/,不要再写转义符了
sed -n 's!/bin/bash!/bin/csh!p' /etc/passwd
#test.txt中有文件 94599
#将94599替换为9893
sed -i 's9\\945\\9\\99\\98\\939g' test.txt
#因为分隔符9 与表达式的内容9重名,所以表达式中的9需要加转义符\\9 来表示 9。
#因此可以这样看 s9 \\945\\9\\9 9 \\98\\93 9g
#用9做分隔符其实不好,重名了,只是为了演示用法
1.6 插入
a: 增加,在当前行下面增加一行指定内容。
i: 插入,在选定行上面插入一行指定内容。
c: 替换,将选定行替换为指定内容。
y: 字符转换,转换前后的字符长度必须相同。
r: 跟文件名,注入文件中的内容
例子:
#将含有字符串45的行,整体替换为 ABC
sed '/45/c ABC' numedfile.txt
#将含有字符串45的行,字符45转换AB
sed '/45/ y/45/AB/' numsedfile.txt
#将含有字符串45的行,字符145转换ABC,字符45转换BC
sed '/45/ y/145/ABC/' numsedfile.txt
1 . 替换
2 . 添加:
#在1-3行每一行上面各添加一行ABCD
sed '1,3i ABCD' numsedfile.txt
#在1-3行每一行下面各添加一行ABCD
sed '1,3a ABCD' numsedfile.txt
从文件中导入数据
#在numsedfile.txt 的第三行后面增加 /root/test.txt 文件中的内容
sed '3r /root/test.txt' numsedfile.txt
#将包含root的行 剪切到末尾,H表示复制到剪切板,G表示粘贴到指定行后
sed '/root/{H;d};$G' /etc/passwd
#将1、2行 复制到 3和4行的下面
sed '1,2H;3,4G' /etc/passwd
先H复制后,用分号; 与G黏贴分开,表示 有先后顺序
去除黏贴后产生的空行
sed '1,2H;3,4G' /etc/passwd | sed '^$d'
二、操作小练习
观察:
# 111 和 222 互换位置
echo "111222333" | sed -r 's/(111)(222)/\\2\\1/'
#第一个 和 倒数第一个互换位置
echo "111222333" | sed -r 's/^(.)(.*)(.)$/\\3\\2\\1/'
根据观察上面的操作结果,完成要求: 使用 sed 将 123ABC 反转,即 CBA321
echo "123ABC" | sed -r 's/^([0-9]{1})(.*)([A-Z])$/\\3\\2\\1/' | sed -r 's/([0-9]{1})(.*)([A-Z])/\\3\\2\\1/' | sed -r 's/([0-9]{1})(.*)([A-Z])/\\3\\2\\1/'
echo "123ABC" | sed -r 's/^(.)(.)(.)(.)(.)(.)$/\\6\\5\\4\\3\\2\\1/'
echo "123ABC" | sed -r 's/^(.)(.*)(.)/\\3\\2\\1/' | sed -r 's/^(.)(.)(.*)(.)(.$)/\\1\\4\\3\\2\\5/' | sed -r 's/^(..)(.)(.)(.*)$/\\1\\3\\2\\4/'
以上是关于流编辑器 sed的主要内容,如果未能解决你的问题,请参考以下文章