三剑客之sed

sed

Stream EDitor
流编辑器,逐行过滤和替换文本
 
工作特点
默认不编辑源文件,仅对模式空间中的数据做处理,处理结束后,将模式空间输出至屏幕
 

工作原理

sed命令将当前处理的行读入自己的模式空间(pattem space)进行处理,处理完把结果打印至屏幕,并清空模式空间,然后再将下一行读入模式空间进行处理输出,以此类推,直到最后一行.
还有一个空间叫保持空间,又称暂存空间,可以暂时存放一些处理的数据,但不能直接输出,只能放到模式空间输出.
这两个空间其实就是在内存中初始化的一个内存区域,存放正在处理的数据和临时存放的数据.
 

使用格式

sed [OPTIONS]... 'script' inputfile...
sed OPTIONS '/PATTERN/COMMAND' FILE_NAME
 

地址定界符

单地址
  n: 指定的行(n为数字)
  /pattern/: 被此处模式所能够匹配到每一行
地址范围
  m,n: 从m到n行
  m,+n: 从第m行到往后n行
  /pat1/,/pat2/: 表示从第一次匹配pattern1模式的行开始,到第一次匹配pattern2模式的行结束,取中间所有的行
  m,/pat1/: 从第m行到第一次匹配到pat1
$: 表示最后一行
# 删除第二行
sed '2d' file

# 删除第二行到最后一行
sed '2,$d' file

# 删除最后一行
sed '$d' file

# 删除文件中以test开头的行
sed '/^test/'d file
 

常用选项(option)

-n: 静默模式,不打印模式空间内的内容
-e script: 多点编辑,允许在同一行里执行多条命令,使用分号;隔开
sed -e '1,5d' -e 's/test/check/' file

# 注: 上面sed表达式的第一条命令删除1至5行,第二条命令用check替换test。命令的执行顺序对结果有影响。如果两个命令都是替换命令,那么第一个替换命令将影响第二个替换命令的结果

# 和 -e 等价的命令是 --expression:
sed --expression='s/test/check/' --expression='/love/d' file
 
-f file: 从指定文件file中读取编辑脚本
sed [options] -f scriptfile file(s)

# sed脚本是一个sed的命令清单,启动Sed时以-f选项引导脚本文件名。Sed对于脚本中输入的命令非常挑剔,在命令的末尾不能有任何空白或文本,如果在一行中有多个命令,要用分号分隔。以#开头的行为注释行,且不能跨行
-r: 支持使用扩展正则表达式
-i: 直接修改原文件(此操作有风险)
 

处理命令(command)

多个处理命令,使用分号;隔开
p: 打印模式空间中的内容,仅打印符合条件的内容,一般配合-n来使用
# 显示/etc/fstab中以/开头的行,/为特殊符号,需转义
sed -n '/^\//p' /etc/fstab
 
d: 删除符合条件的行(模式空间中的行)
# 删除文件/etc/fstab中第一行,把剩下的内容显示到屏幕上,原文件内容不会发生任何改变
sed '1d' /etc/fstab

# 删除带有oot的行,如果匹配字符串,需要用/隔开
sed ‘/oot/d' /etc/fstab
 
a \'text': 在行后面追加文本,支持使用\n换行符实现多行追加
i \'text': 在行前面插入文本,支持使用\n换行符实现多行插入
c \'text': 替换符合条件的行为单行或多行文本
w /path/to/somefile: 保存模式空间中的内容至指定文件中
r /path/from/somefile: 读取指定文件的文本流至模式空间中的行后
# 将文件/etc/fstab中包含有oot的行另存至文件/tmp/oot.txt文件中
sed '/oot/w /tmp/oot.txt' /etc/fstab

# 把/etc/issue文件的内容添加到/etc/fstab文件内容第二行的后面
sed '2r /etc/issue' /etc/fstab 
 
=: 显示符合条件的行的行号,为模式空间中的行打印行号
D: 删除多行模式空间中的所有行
h: 把模式空间中的内容覆盖至保持空间中
H: 把模式空间中的内容追加至保持空间中
g: 从保持空间取出数据并覆盖至模式空间中
G: 从保持空间取出内容并追加至模式空间中
x: 把模式空间中的内容与保持空间中的内容进行互换
n: 读取匹配到的行的下一行至模式空间
N: 追加匹配到的行的下一行至模式空间
cat test.txt
"""
1
2
3
4
5
6
"""

# 逆序显示文本内容
sed '1!G;h;$!d' test.txt
"""
说明:
读第一行,将第一行读取到自己的模式空间中:
1!G是指除了第一行,其他行都从保持空间取出并追加至模式空间中,那么第一行不会追加;
h是把模式空间中的第一行数据覆盖至保持空间中,此时保持空间中有了第一行数据,此时,模式空间和保持空间都有了第一行数据;
$!d是指除了最后一行都删除,那么模式空间中的数据不是最后一行,则执行后面删除操作

读第二行至模式空间中:
先从保持空间中取出第一行的数据,追加到模式空间中,此时模式空间中有了第二行数据和第一行数据,然后执行h,模式空间中的内容覆盖至保持空间中,此时保持空间中的数据从上到下,有了第二行数据,第一行数据,最后判断是否为最后一行,否则删除;

以此类推,当读取到最后一行数据至模式空间中:
此时的模式空间中存在的是最后一行数据,而保持空间中按从上到下顺序应该是:倒数第二行数据,倒数第三行数据,...,然后执行G,从保持空间取出内容并追加至模式空间中,此时的模式空间中的数据则形成了倒序的方式,然后执行h,把模式空间中的内容覆盖至保持空间中,此时模式和保持空间的数据都是以倒序的方式存放的数据,最后判断是否为最后一行,很明显是最后一行,那么就不会再执行删除操作

最后打印出模式空间中的内容
"""

# 取出最后1行
sed '$!d' /etc/passwd

# 取出最后2行
sed '$!N;$!D' /etc/passwd

# 每一行后面追加一个空白行
sed 'G' /etc/passwd

# 全部替换成空白行
sed 'g' /etc/passwd

# 显示偶数行
sed -n 'n;p' test.txt

# 显示奇数行
sed 'n;d' /etc/passwd

# 删除原有的所有空白行,而后为所有的非空白行后添加一个空白行
sed '/^$/d;G' /etc/passwd

# 删除原有的所有空白行,而后为所有的非空白行后添加一个空白行
sed '/^$/d;G' /etc/passwd

# 显示最后一行的行号,一般可用于显示文本的总行
sed -n '$=' /etc/fstab

# 显示所有行的行号,但空行不显示行号
sed '/./=' /etc/fstab
示例
 
s/old/new/: 查找替换,替换old为new,其中/可以自定义,比如也可以写成s@@@,s###等
替换标记:
g: 行内全局替换(s///g),即替换所有匹配到的字符串
p: 显示替换成功的行(s///p)
w FILE: 将替换成功的结果保存至文件中
i: 忽略字符大小写
&: 表示引用匹配到的内容
!: 取反条件
\w+ 匹配每一个单词
# 查找文件sftab含有oot的行全部替换成OOT,默认只替换每行第一次被模式匹配到的串
sed 's/oot/OOT/' /etc/fstab

# 查找文件fstab中,/开头的字符串,把/全部换成*sed 's/^\//*/g' /etc/fstab 表示

# 符合l..e模式的字符串,在后面添加一个er
sed '[email protected]@&er@' /etc/fstab
sed 's#\(l..e\)#\1er#g' /etc/fstab

# 将每个单词使用方括号[]括起来
echo 'this is a test line' | sed 's/\w\+/[&]/g'
"""
[this] [is] [a] [test] [line]
""'

# 替换'digit 7''6'
echo 'this is digit 7 in number.' | sed 's@digit \([0-9]\)@\1@'

# 查找/etc/fstab文件中,UUID和tmpfs之间的行,每行的行尾加上字符串aaa bbb
sed '/UUID/,/tmpfs/s@$@aaa bbb@' /etc/fstab

# 查找line1到line2之间的所有aa bbb 替换为AA BBB
sed '/line1/,/line2/s@aa bbb@AA BBB@' file_name

# 显示第一次匹配到的3,到最后一行输出
sed -n '/3/,$p' file_name

# 显示第一次匹配到的3,到向下2行输出
sed -n '/3/,+2p' file_name
示例
:
所有的处理命令均是在sed自己的模式空间内操作
要想同步修改目标文件内容,需要加上-i选项
 

练习题

# 删除/boot/grub/grub.conf文件中所有以空白开头的行的行首的空白字符
sed 's#^[[:space:]]\+##' /boot/grub/grub.confsed

# 删除/etc/fstab文件中所有以#开头,后面至少跟一个空白字符的行的行首的#和空白字符
sed 's@^#[[:space:]]\+@@' /etc/fstab

# echo一个绝对路径给sed命令,取出其基名,取出其目录名
echo '/etc/sysconfig/network' | sed 's@[^/]\+/\?$@@'

# 删除文件/etc/init.d/inittab中所有的数字
sed 's/[[:digit:]]\+//g' /etc/init.d/inittab

# 将时间格式 yy/mm/dd 的日期格式换成 yy:mm:dd的格式
date +"%Y/%m/%d" |sed -n 's#/#:#gp'

# 显示奇数行
sed -n '1~2p' file_name

# 显示偶数行
sed -n '2~2p' file_name

# 删除模式一到模式二匹配到的行
sed '/^aaa/,/^eee/d' file_name

# 从指定行开始开始,每隔2行显示一次
sed -n '2,${p;n;n}' file_name

# 删除一个文件中所有的数字
sed 's/[[:digit:]]\+//g' /etc/init.d/inittab

# 将时间格式 yy/mm/dd 的日期格式换成 yy:mm:dd的格式
date +"%Y/%m/%d" |sed -n 's#/#:#gp'

# 显示奇数行
sed -n '1~2p' file

# 删除模式一到模式二匹配到的行
sed '/^aaa/,/^eee/d' File

# 从指定行开始开始,每隔2行显示一次
sed -n '2,${p;n;n}' File

# 删除文中的最后两行
sed 'N;$!P;$!D;$d' /etc/passwd

# 删除文中的空行
sed '/./!d' /etc/fstab

# 每隔5行增加一个空行
sed 'n;n;n;n;G;' File

# 不显示指定字符开始的行
sed -n '/^aaa\+/!p' File

# 查找文件中1到20行之间,同时将”aaa”替换为”AAA” ,”ddd”替换”DDD”
sed -nr 's/(.*)([^a-Z]+)([a-Z]+)([^a-Z]*)/\1\2\4/p' /etc/passwd

# 替换文本中的字符串
echo "sksksksksksk" | sed 's/sk/SK/3g
练习1
cat test
"""
1 nimgtw         48003/udp               # Nimbus Gateway
2 3gpp-cbsp       48049/tcp               # 3GPP Cell Broadcast Service Protocol
3 isnetserv       48128/tcp               # Image Systems Network Services
4 isnetserv       48128/udp               # Image Systems Network Services
5 blp5           48129/tcp               # Bloomberg locator
6 blp5           48129/udp               # Bloomberg locator
7 com-bardac-dw     48556/tcp               # com-bardac-dw
8 com-bardac-dw     48556/udp               # com-bardac-dw
9 iqobject        48619/tcp               # iqobject
10 iqobject        48619/udp               # iqobject
"""

# 打印匹配'blp5'开头的行
sed -n '/^blp5/p' test

# 打印出第一行
sed -n '1p' test

# 打印出第1行到第3行
sed -n '1,3p'

# 打印出奇数行
sed -n '1~2p' test

# 打印出偶数行
sed -n '2~2p' test

# 打印匹配的行和它后面的一行
sed -n '/nimgtw/,+1p' test

# 打印最后一行
sed -n '$p' test

# 打印所有行,除了最后一行
sed -n '$!p' test

# 匹配范围
sed -n '/^blp5/,/^com/p' test

# 匹配开头行到最后一行
sed -n '/^blp5/,$p' test

# 引用变量,来匹配行
a = 1
sed -n ''$a',3p' test
# 注意:sed后面跟单引号,变量需要单引号才能引用,sed后面用双引号,变量则无需引号也会被引用

# 匹配删除
sed '/blp5/d' test

# 匹配删除奇数行
sed '1~2d' test

# 匹配删除第1行到第3行
sed '1,3d' test

# 替换blp5为test
sed 's/blp5/test/g' test

# 替换开头是blp5的行并打印
sed -n 's/^blp5/test/p' test

# 引用匹配内容并替换
sed 's/^blp5/&00000000/' test

# ip加单引号
echo '10.10.10.1 10.10.10.2 10.10.10.3' | sed -r 's/[^ ]+/"&"/g'

# 对1-5行的blp5进行替换
sed '1,5s/blp5/test/' test

# 对匹配行进行替换,查找tcp且开头是com的行,替换成COM
sed '/tcp/s/^com/COM/' test

# 多次匹配并替换
sed 's/blp5/test/;s/3g/4g/' test

# 将协议与端口号位置调换(不明白)
sed -r 's/(.*)(\<[0-9]+\>)\/(tcp|udp)(.*)/\1\3\/\2\4/' test

# 注释掉匹配行后面的指定行数
seq 10 | sed '/5/,+3s/^/#/'
练习2
# 将 error.log中匹配到的内容保存至某个文件中:
sed -n '/root/w file.txt' error.log

# 将文件中的内容读入到匹配的内容后面
sed '/root/r abc.txt' /etc/passwd

# 打印匹配到的内容,并显示行号
sed -n '/root/{=;p}' /etc/passwd

# 删除匹配到的行的下一行
sed -n '/UUID/{n;d}' /etc/fstab

# 删除匹配到的行和下一行
sed '/UUID/{N;d}' /etc/fstab

# 删除文件每行中的第一个字符
sed -n 's/^.//gp' /etc/fstab

# 删除文件每行的第二个字符
sed -nr 's/(.)(.)(.*)/\1\3/p' /etc/passwd

# 删除文件每行的最后一个字符
sed -nr 's/.$//p' /etc/passwd

# 删除每行的最后一个单词
sed -nr 's/(.*)([^a-Z]+)([a-Z]+)([^a-Z]*)/\1\2\4/p' /etc/passwd

# 将file文件中的内容,实现最终效果,如下:
cat file
"""
aaa
bbb
ccc
ddd
eee
fff
ggg
hhh
"""
# 实现如下效果:
cat file
"""
aaa bbb
ccc ddd
eee fff
ggg hhh
"""

# 实现方法
sed 'N;s/\n/\t/' b.tx

# 实现原理:
# N:读取下一行并追加到模式空间中的行后面,当Sed读入第一行内容时,由N将下一行的内容追加到模式空间中,此时模式空间的内容为“aaa\nbbb”,再由编写的匹配规则进行替换将”\n”替换为了”\t”,再执行默认的”p”操作,输出到标准输出
练习3

猜你喜欢

转载自www.cnblogs.com/xiaofeiweb/p/8953732.html