文本三剑客之sed

295 阅读5分钟

1. sed编辑器

sed是一种流编辑器,流编辑器会在编辑器处理数据之前基于预先提供的一组规则来编辑数据流。

sed编辑器可以根据命令来处理数据流中的数据,这些命令要么从命令行中输入,要么存储在一个命令文本文件中。

1.1 sed的工作流程

主要包括读取、执行和显示三个过程

  • 读取:sed从输入流(文件、管道、标准输入)中读取一行内容并存储到临时的缓冲区中(又称模式空间,patternspace)
  • 执行:默认情况下,所有的sed命令都在模式空间中顺序地执行,除非指定了行的地址,否则sed命令将会在所有的行上依次执行。
  • 显示:发送修改后的内容到输出流。在发送数据后,模式空间将会被清空。在所有的文件内容都被处理完成之前,上述过程将重复执行,直至所有内容被处理完。

在所有的文件内容都被处理完成之前,上述过程将重复执行,直至所有内容被处理完。

注意:默认情况下所有的sed命令都是在模式空间内执行的,因此输入的文件并不会发生任何变化,除非是用重定向存储输出。

1.2 命令格式

  1. sed -e '操作' 文件1 文件2 ...

  2. sed -n -e '操作' 文件1 文件2 ...

  3. sed -f 脚本文件 文件1 文件2 ...

  4. sed -i -e '操作' 文件1 文件2 ...

  5. sed -e 'n{

操作1

操作2

...

}' 文件1 文件2 ...

1.3 常用选项

选项说明
e或--expression=表示用指定命令来处理输入的文本文件,只有一个操作命令时可省略,一般在执行多个操作命令使用
f 或--file=表示用指定的脚本文件来处理输入的文本文件。
h或--help显示帮助。
n、--quiet或silent禁止sed编辑器输出,但可以与p命令一起使用完成输出。
i直接修改目标文本文件。

1.4 常用操作

选项说明
s替换,替换指定字符。
d删除,删除选定的行。
a增加,在当前行下面增加一行指定内容。
i插入,在选定行,上面插入一行指定内容。
c替换,将选定行替换为指定内容。
y字符转换,转换前后的字符长度必须相同。
p打印,如果同时指定行,表示打印指定行:如果不指定行,则表示打印所有内容;如果有非打印字符,则以ASCII码输出。其通常与“-n”选项一起使用。
=打印行号
l(小写L)打印数据流中的文本和不可打印的ASCII字符(比如结束符$、制表符\t)

2. 打印内容

  • 示例
[root@localhost ~]# cat testfile1 

image.png

[root@localhost ~]# sed -n -e '=;p' testfile1   //显示行号并且输出内容,操作用;隔开
1
one
2
two
3
three
4
four
5
five
6
six
7
seven
8
eight
9
nine
10
ten
11
eleven
12
twelve
[root@localhost ~]# sed -n -e 'l' testfile1   //打印数据流中的文本,以$结尾
one$
two$
three$
four$
five$
six$
seven$
eight$
nine$
ten$
eleven$
twelve$
[root@localhost ~]# sed -n -e 'p' testfile1  //打印输出内容
one
two
three
four
five
six
seven
eight
nine
ten
eleven
twelve
[root@localhost ~]# sed 'p' testfile1  //不加任何选项,会输出两遍
one
one
two
two
three
three
four
four
five
five
six
six
seven
seven
eight
eight
nine
nine
ten
ten
eleven
eleven
twelve
twelve

3. 使用地址

  • sed编辑器有2种寻址方式
  1. 以数字形式表示行区间
  2. 用文本模式来过滤出行
  • 示例
[root@localhost ~]# cat testfile1 

image.png

[root@localhost ~]# cp e testfile1
[root@localhost ~]# sed -n '1p' testfile1    //显示第一行
one
[root@localhost ~]# sed -n '$p' testfile1    //显示最后一行
twelve
[root@localhost ~]# sed -n '1,3p' testfile1   //从第一行到第三行
one
two
three
[root@localhost ~]# sed -n '3,$p' testfile1   //从第三行开始到最后一行
three
four
five
six
seven
eight
nine
ten
eleven
twelve
[root@localhost ~]# sed -n '1,+3p' testfile1   //打印第1行之后的连续3行,即1-4行
one
two
three
four
[root@localhost ~]# sed '5q' testfile1    //打印前5行信息后退出
one
two
three
four
five
[root@localhost ~]# sed -n 'p;n' testfile1  //隔行读取
one
three
five
seven
nine
eleven
[root@localhost ~]# sed -n '2,${n;p}' testfile1  //'2,$p'从第二行开始到最后一行,但是在{}里遇到了n所以要换下一行,所以从第三行开始隔行打印
three
five
seven
nine
eleven

注:sed -n 'p;n' testfile1 p:打印,n:换下一行

  • 示例:可以使用正则打印
[root@localhost ~]# sed -n '/en$/p' testfile1  //打印以en结尾的行数
seven
ten
eleven

4. 删除行

  • 行号删除
[root@localhost ~]# sed 'd' testfile1    //全删
[root@localhost ~]# sed '3d' testfile1   //删除第三行
one
two
four
five
six
seven
eight
nine
ten
eleven
twelve
[root@localhost ~]# sed '2,4d' testfile1  //从第二行开始删除4行
one
five
six
seven
eight
nine
ten
eleven
twelve
[root@localhost ~]# sed '$d' testfile1   //删除最后一行
one
two
three
four
five
six
seven
eight
nine
ten
eleven
[root@localhost ~]# sed '/^$/d' testfile1   //删除空行
one
two
three
four
five
six
seven
eight
nine
ten
eleven
twelve

  • 范围删除(谨慎使用)
[root@localhost ~]# sed '/nologin/d' /etc/passwd //删除带有nologin的一行
[root@localhost ~]# sed '/nologin/!d' /etc/passwd    //!表示取反操作
[root@localhost ~]# sed '/2/,/3/d' testfile2     //从第一个位置打开行删除功能,到第1个位置关闭行删除功能

image.png

5. 替换

  • 格式

行范围 s/旧字符串/新字符串/替换标记

  • 4种替换标记
  1. 数字:表明新字符串将替换第几处匹配的地方
  2. g:表明新字符串将会替换所有匹配的地方
  3. p:打印与替换命令匹配的行,与-n一起使用
  4. w 文件:将替换的结果写到文件中(另保存)
[root@localhost ~]# sed -n 's/root/admin/p' /etc/passwd   //替换匹配的第一个root变成admin
admin:x:0:0:root:/root:/bin/bash
operator:x:11:0:operator:/admin:/sbin/nologin
[root@localhost ~]# sed -n 's/root/admin/2p' /etc/passwd  //替换匹配的第二个root变成admin
root:x:0:0:admin:/root:/bin/bash
[root@localhost ~]# sed -n 's/root/admin/gp' /etc/passwd  //替换匹配所有root变成admin
admin:x:0:0:admin:/admin:/bin/bash
operator:x:11:0:operator:/admin:/sbin/nologin
[root@localhost ~]# sed -n 's/root//gp'  /etc/passwd  //替换匹配所有root为空
:x:0:0::/:/bin/bash
operator:x:11:0:operator:/:/sbin/nologin
[root@localhost ~]# sed '1,20 s/^/#/' /etc/passwd  //1-20行开头替换成#
#root:x:0:0:root:/root:/bin/bash
#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
#sync:x:5:0:sync:/sbin:/bin/sync
#shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown
#halt:x:7:0:halt:/sbin:/sbin/halt
#mail:x:8:12:mail:/var/spool/mail:/sbin/nologin
#operator:x:11:0:operator:/root:/sbin/nologin
#games:x:12:100:games:/usr/games:/sbin/nologin
#ftp:x:14:50:FTP User:/var/ftp:/sbin/nologin
#nobody:x:99:99:Nobody:/:/sbin/nologin
#systemd-network:x:192:192:systemd Network Management:/:/sbin/nologin
#dbus:x:81:81:System message bus:/:/sbin/nologin
#polkitd:x:999:997:User for polkitd:/:/sbin/nologin
#abrt:x:173:173::/etc/abrt:/sbin/nologin
#libstoragemgmt:x:998:995:daemon account for libstoragemgmt:/var/run/lsm:/sbin/nologin
#rpc:x:32:32:Rpcbind Daemon:/var/lib/rpcbind:/sbin/nologin
#colord:x:997:994:User for colord:/var/lib/colord:/sbin/nologin
[root@localhost ~]# sed '/^root/ s/$/#/' /etc/passwd  //匹配以root开头行,替换最后为#

image.png

[root@localhost ~]# sed -rn 's/.*root.*/#&/p' /etc/passwd

image.png

[root@localhost ~]# sed 's/\b[a-z]/\u&/g' testfile1

image.png

[root@localhost ~]# sed 's/[a-z]/\u&/g' testfile1 

image.png

[root@localhost ~]# sed 's/[A-Z]/\l&/g' testfile1

image.png

[root@localhost ~]# sed '1,5w out.txt' testfile1 
[root@localhost ~]# cat out.txt

image.png

[root@localhost ~]# sed '1,5 s/^/#/w out2.txt' testfile1 
[root@localhost ~]# cat out2.txt 

image.png

  • 替换时sed分隔符的使用特点

注:分隔时s后跟的任意符号都可以当作分隔符(数字,字母,符号),不一定非得是/号

image.png

image.png

[root@localhost ~]# sed '/72/c ABC' testfile2

image.png

[root@localhost ~]# sed 'y/123/ABC/' testfile2

image.png

  • 面试题

问:sed -i 's9\945\9\998\939g' test命令执行以后会发生什么?

image.png

6. 插入

[root@localhost ~]# sed '1,3a ABC' testfile2 

image.png

[root@localhost ~]# sed '1i ABC' testfile2

image.png

[root@localhost ~]# sed '5r /root/testfile1' testfile2 

image.png

[root@localhost ~]# sed '/1/{H;d};$G' testfile2    //将包含1的行剪切到末尾,H表示复制到剪切板,G表示粘贴到指定行后

image.png

[root@localhost ~]# sed '1,2H;3,4G' testfile2

image.png

[root@localhost ~]# echo "111222333" | sed -r 's/(111)(222)(333)/\3\2\1/'

image.png

[root@localhost ~]# echo "abc" | sed -r 's/^(.)(.)(.)$/\3\2\1/'

image.png

注:带有特殊意义的符号要么在符号前加上\号,要么在选项里加上-r

7. 总结

行范围 s/旧字符串/新字符串/替换标记  
s/旧字符串/新字符串/2  #代表对每行第二个匹配到的字符串进行替换                   
                  g  #代表对每行所有能匹配到的字符进行替换                   
                  p  #可以结合-n 选项只打印替换的行内容                   
                  w  #可以把替换的行内容保存到指定的文件中                    
n,m s/旧字符串/新字符串/       #指定第n行到第m行,将旧字符串替换成新字符串  
/字符串+正则/ s/旧字符串/新字符串/    #过滤出想要的行,之后进行替换
s/^/添加的字符/    #行首添加内容  
s/$/添加的字符/    #行尾添加内容 
sed -f 文件    #指定脚本文件来执行,可以在文件中定义多条操作规则  
sed指定字符串的分隔符,就看s后面跟的字符,3个分隔符要保持一致,如果遇到跟分隔符相同的字符则需要使用\来转义。 
例如:s#/bin/bash#/sbin/nologin#g