Shell之sed编辑器

Shell之sed编辑器

一、sed编辑器

1. sed编辑器概述

sed是一种流编辑器,流编辑器会在编辑器处理数据之前基于预先提供的一组规则来编辑数据流。
sed编辑器可以根据命令来处理数据流中的数据,这些命令要么从命令行中输入,要么存储在一个命令文本中。

2. sed编辑器的工作流程

sed的工作流程主要包括读取、执行和显示三个过程。

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

二、sed命令

1. 命令格式

sed -e '操作' 文件1 文件2 ...
sed -n -e '操作' 文件1 文件2 ...
sed -f 脚本文件 文件1 文件2 ...
sed -i -e '操作' 文件1 文件2 ...

2. 常用选项

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

3. 常用操作

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

三、操作实例

1. 打印内容

sed -n -e 'p' 文件名
打印文本内容

[root@gh date]# sed -n -e 'p' test1.txt
one
two
three
four
five
six

sed -n -e '=' 文件名
仅打印行号

[root@gh date]# sed -n -e '=' test1.txt
1
2
3
4
5
6

sed -n -e 'l' 文件名
打印文本并显示结束符

[root@gh date]# sed -n -e 'l' test1.txt
one$
two$
three$
four$
five$
six$

(1)sed -n -e '=;p' 文件名

(2)sed -n -e '=' -e 'p' 文件名

(3)sed -n '
> =
> p
> ' 文件名

显示行号再打印文本

[root@gh date]# sed -n -e '=;p' test1.txt
1
one
2
two
3
three
4
four
5
five
6
six

2. 使用地址

sed编辑器有2种寻址方式:

  1. 以数字形式表示行区间
  2. 用文本模式来过滤此行

sed -n '1p' 文件名
打印指定行内容

[root@gh date]# sed -n '1p' test1.txt 
one

sed -n '$p' 文件名
打印最后一行内容

[root@gh date]# sed -n '$p' test1.txt 
six

sed -n '1,3p' 文件名
打印一到三行内容

[root@gh date]# sed -n '1,3p' test1.txt 
one
two
three

sed -n '3,$p' 文件名
从第3行打印至末尾行

[root@gh date]# sed -n '3,$p' test1.txt 
three
four
five
six

sed -n '1,+3p' 文件名
打印第一行以及后面的三行,即打印1-4行

[root@gh date]# sed -n '1,+3p' test1.txt
one
two
three
four

sed '5q' 文件名
打印前5行后退出,q表示退出

[root@gh date]# sed '5q' test1.txt
one
two
three
four
five

sed -n 'p;n' 文件名
打印奇数行,p为打印,n为移动至下一行

[root@gh date]# sed -n 'p;n'  test1.txt
one
three
five

sed -n 'n;p' 文件名
打印偶数行,n为移动至下一行,p为打印

[root@gh date]# sed -n 'n;p'  test1.txt
two
four
six

sed -n '2,${n;p}' 文件名
从第二行至末尾行,按照隔一行打印的顺序执行

[root@gh date]# sed -n '2,${n;p}' test1.txt 
three
five

sed -n '/user/p' 文件名
打印含有user的行

[root@gh date]# sed -n '/user/p' /etc/passwd
saslauth:x:996:76:Saslauthd user:/run/saslauthd:/sbin/nologin
qemu:x:107:107:qemu user:/:/sbin/nologin
radvd:x:75:75:radvd user:/:/sbin/nologin
tss:x:59:59:Account used by the trousers package to sandbox the tcsd daemon:/dev/null:/sbin/nologin
usbmuxd:x:113:113:usbmuxd user:/:/sbin/nologin
rpcuser:x:29:29:RPC Service User:/var/lib/nfs:/sbin/nologin

sed -n '/^a/p' 文件名
打印以a开头的行

[root@gh date]# sed -n '/^a/p' /etc/passwd
adm:x:3:4:adm:/var/adm:/sbin/nologin
abrt:x:173:173::/etc/abrt:/sbin/nologin
avahi:x:70:70:Avahi mDNS/DNS-SD Stack:/var/run/avahi-daemon:/sbin/nologin
apache:x:48:48:Apache:/usr/share/httpd:/sbin/nologin

sed -n '/a$/p' 文件名
打印以a结尾的行

[root@gh date]# sed -n '/bash$/p' /etc/passwd
root:x:0:0:root:/root:/bin/bash
123456:x:1000:1000:123456:/home/123456:/bin/bash

sed -n '/a|b/p' 文件名
打印含有a或b的行

[root@gh date]# sed -n '/ftp\|root/p' /etc/passwd
root:x:0:0:root:/root:/bin/bash
operator:x:11:0:operator:/root:/sbin/nologin
ftp:x:14:50:FTP User:/var/ftp:/sbin/nologin

sed -n '2,/a/p' 文件名
从第2行打印至含有a的行

[root@gh date]# sed -n '2,/nologin/p' /etc/passwd
bin:x:1:1:bin:/bin:/sbin/nologin
daemon:x:2:2:daemon:/sbin:/sbin/nologin

sed -n '2,/a/=' 文件名
打印第二行至含有a的行的行号

[root@gh date]# sed -n '2,/nologin/=' /etc/passwd
2
3

sed -nr '/ro{1,}t/p' 文件名
打印含有ro{1个或多个o}t的行,-r表示支持扩展正则表达式

[root@gh date]# sed -nr '/ro{1,}t/p' /etc/passwd
root:x:0:0:root:/root:/bin/bash
operator:x:11:0:operator:/root:/sbin/nologin

3. 删除行

sed 'd' 文件名
删除全部

[root@gh date]# sed 'd' test1.txt 
[root@gh date]# 

sed '3d' 文件名
删除第3行

[root@gh date]# sed '3d' test1.txt 
one
two
four
five
six

sed '2,4d' 文件名
删除2至4行

[root@gh date]# sed '2,4d' test1.txt 
one
five
six

sed '$d' 文件名
删除末尾行

[root@gh date]# sed '$d' test1.txt 
one
two
three
four
five

sed '/^$/d' 文件名
删除空行

[root@gh date]# cat test1.txt 
one
two
 
three
four
 
five
six
[root@gh date]# sed '/^$/d' test1.txt 
one
two
three
four
five
six

sed '/a$/d' 文件名
删除以a结尾的行

[root@gh date]# sed '/nologin$/d' /etc/passwd
root:x:0:0:root:/root:/bin/bash
sync:x:5:0:sync:/sbin:/bin/sync
shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown
halt:x:7:0:halt:/sbin:/sbin/halt
gh:x:1000:1000:gh:/home/gh:/bin/bash

sed '/a$/!d' 文件名
删除不是以a结尾的行,!表示取反操作

[root@gh date]# sed '/nologin$/!d' /etc/passwd|tail
ntp:x:38:38::/etc/ntp:/sbin/nologin
sssd:x:991:985:User for sssd:/:/sbin/nologin
setroubleshoot:x:990:984::/var/lib/setroubleshoot:/sbin/nologin
saned:x:989:983:SANE scanner daemon user:/usr/share/sane:/sbin/nologin
gdm:x:42:42::/var/lib/gdm:/sbin/nologin
gnome-initial-setup:x:988:982::/run/gnome-initial-setup/:/sbin/nologin
sshd:x:74:74:Privilege-separated SSH:/var/empty/sshd:/sbin/nologin
avahi:x:70:70:Avahi mDNS/DNS-SD Stack:/var/run/avahi-daemon:/sbin/nologin
postfix:x:89:89::/var/spool/postfix:/sbin/nologin
tcpdump:x:72:72::/:/sbin/nologin

sed '/a/,/b/d' 文件名
从含有位置1的行开启删除功能,到含有位置2的行关闭删除功能,并在含有位置1的行再次出现后开启删除功能,循环往复。若不再出现含有位置2的行,则删除功能不会停止。
即从含有a的行开启删除,直到含有b的行出现关闭删除功能并在下一个含有a的行再次开启删除功能,循环往复。若不再出现含有b的行,则删除功能不会停止。

[root@gh date]# cat test1.txt 
1
2
3
4
5
6
11
22
33
111
222
444
555
666
[root@gh date]# sed '/2/,/3/d' test1.txt 
1
4
5
6
11
111

4. 替换

一般格式为:sed 行范围 s/旧字符串/新字符串/替换标记
替换标记有:

  1. 数字:表明新字符串将替换第几处匹配的地方
  2. g:表明新字符串将会替换所有匹配的地方
  3. p:打印与替换命令匹配的行,与-n一起使用
  4. w 文件:将替换的结果写到文件中,若需要保存全部结果,可使用重定向输入

sed -n 's/1/2/p' 文件名
将每行的第一个字符串1替换为字符串2

[root@gh date]# sed -n 's/root/admin/p' /etc/passwd
admin:x:0:0:root:/root:/bin/bash
operator:x:11:0:operator:/admin:/sbin/nologin

sed -n 's/1/2/2p' 文件名
将每行的第2个字符串1替换为字符串2

[root@gh date]# sed -n 's/root/admin/2p' /etc/passwd
root:x:0:0:admin:/root:/bin/bash

sed -n 's/1/2/gp' 文件名
将全部的字符串1替换为字符串2

[root@gh date]# sed -n 's/root/admin/gp' /etc/passwd
admin:x:0:0:admin:/admin:/bin/bash
operator:x:11:0:operator:/admin:/sbin/nologin

sed 's/1//g' 文件名
将全部的字符串1替换为空,即删除全部的字符串1

[root@gh date]# sed 's/root//g' /etc/passwd|tail
sssd:x:991:985:User for sssd:/:/sbin/nologin
setroubleshoot:x:990:984::/var/lib/setroubleshoot:/sbin/nologin
saned:x:989:983:SANE scanner daemon user:/usr/share/sane:/sbin/nologin
gdm:x:42:42::/var/lib/gdm:/sbin/nologin
gnome-initial-setup:x:988:982::/run/gnome-initial-setup/:/sbin/nologin
sshd:x:74:74:Privilege-separated SSH:/var/empty/sshd:/sbin/nologin
avahi:x:70:70:Avahi mDNS/DNS-SD Stack:/var/run/avahi-daemon:/sbin/nologin
postfix:x:89:89::/var/spool/postfix:/sbin/nologin
tcpdump:x:72:72::/:/sbin/nologin
gh:x:1000:1000:gh:/home/gh:/bin/bash

sed '1,20 s/^/#/' 文件名
将1到20行的开头替换为#

[root@gh date]# sed '1,5 s/^/#/' /etc/passwd|head
#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

sed '/^root/ s/$/#/' 文件名
将以root开头的行的末尾替换为#

[root@gh date]# sed '/^root/ s/$/#/' /etc/passwd|tail
sssd:x:991:985:User for sssd:/:/sbin/nologin
setroubleshoot:x:990:984::/var/lib/setroubleshoot:/sbin/nologin
saned:x:989:983:SANE scanner daemon user:/usr/share/sane:/sbin/nologin
gdm:x:42:42::/var/lib/gdm:/sbin/nologin
gnome-initial-setup:x:988:982::/run/gnome-initial-setup/:/sbin/nologin
sshd:x:74:74:Privilege-separated SSH:/var/empty/sshd:/sbin/nologin
avahi:x:70:70:Avahi mDNS/DNS-SD Stack:/var/run/avahi-daemon:/sbin/nologin
postfix:x:89:89::/var/spool/postfix:/sbin/nologin
tcpdump:x:72:72::/:/sbin/nologin
gh:x:1000:1000:gh:/home/gh:/bin/bash

sed -f 脚本文件 处理文件
使用脚本文件对处理文件进行sed操作

[root@gh date]# cat script.sed
/^root/ s/^/#/
/nologin/ s/nologin/false/
[root@gh date]# sed -f script.sed /etc/passwd|head
#root:x:0:0:root:/root:/bin/bash
bin:x:1:1:bin:/bin:/sbin/false
daemon:x:2:2:daemon:/sbin:/sbin/false
adm:x:3:4:adm:/var/adm:/sbin/false
lp:x:4:7:lp:/var/spool/lpd:/sbin/false
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/false
operator:x:11:0:operator:/root:/sbin/false

sed '1,5w 保存文件' 处理文件
将处理文件的1至5行写入到保存文件

[root@gh date]#  sed '1,5w sed.txt' /etc/passwd|head
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
[root@gh date]# cat sed.txt
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

sed '1,20 s/^/#/w 保存文件' 处理文件
将处理文件的1至20行开头替换为#并写入到保存文件

[root@gh date]# sed '1,5 s/^/#/w sed1.txt' /etc/passwd|head
#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
[root@gh date]# cat sed1.txt
#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

sed -n 's//a/b//c/d/p' 文件名
将文件中的/a/b替换为/c/d
注:字符串分隔符可用其他任意字符代替,例如"!"、"#"、" "、"1"等。

[root@gh date]# sed -n 's/\/bin\/bash/\/bin\/sed/p' /etc/passwd
root:x:0:0:root:/root:/bin/sed
gh:x:1000:1000:gh:/home/gh:/bin/sed

[root@gh date]# sed -n 's!/bin/bash!/bin/sed!p' /etc/passwd
root:x:0:0:root:/root:/bin/sed
gh:x:1000:1000:gh:/home/gh:/bin/sed

[root@gh date]# sed -n 's#/bin/bash#/bin/sed#p' /etc/passwd
root:x:0:0:root:/root:/bin/sed
gh:x:1000:1000:gh:/home/gh:/bin/sed

[root@gh date]# sed -n 's /bin/bash /bin/sed p' /etc/passwd
root:x:0:0:root:/root:/bin/sed
gh:x:1000:1000:gh:/home/gh:/bin/sed

[root@gh date]# echo 94599 >test.txt 
[root@gh date]# cat test.txt 
94599
[root@gh date]# sed -i 's9\945\9\99\98\939g' test.txt 
[root@gh date]# cat test.txt 
9893

5. 插入

sed '/a/c b' 文件名
将含有字符串a的行替换为字符串b

[root@gh date]# cat test1.txt
11
26
7
76
99
43
68
678
[root@gh date]# sed '/7/c aa' test1.txt
11
26
aa
aa
99
43
68
aa

sed '/a/ y/b/c/' 文件名
将含有a的行中的字符b替换为字符c,b与c的字符长度要相同

[root@gh date]# cat test1.txt
11
26
7
76
99
43
68
678
[root@gh date]# sed '/7/ y/6/a/' test1.txt
11
26
7
7a
99
43
68
a78

sed 'n,ma b' 文件名
在第n行至第m行后插入字符b

[root@gh date]# cat test1.txt
11
26
7
76
99
43
68
678
[root@gh date]# sed '1,3a aaa' test1.txt
11
aaa
26
aaa
7
aaa
76
99
43
68
678

sed 'ni a' 文件名
在第n行插入字符串a

[root@gh date]# cat test1.txt
11
26
7
76
99
43
68
678
[root@gh date]# sed '2i aaa' test1.txt
11
aaa
26
7
76
99
43
68
678

sed 'nr 插入文件' 文件名
在第n行后插入文件

[root@gh date]# cat test2.txt
aaaaaaa
[root@gh date]# cat test1.txt
11
26
7
76
99
43
68
678
[root@gh date]# sed '3r test2.txt' test1.txt
11
26
7
aaaaaaa
76
99
43
68
678

sed '/a/{H;d};$G' 文件名
将包含a的行剪切到末尾,H表示复制到剪切板,G表示粘贴到指定行后

[root@gh date]# sed '/root/{H;d};$G' /etc/passwd|tail
gdm:x:42:42::/var/lib/gdm:/sbin/nologin
gnome-initial-setup:x:988:982::/run/gnome-initial-setup/:/sbin/nologin
sshd:x:74:74:Privilege-separated SSH:/var/empty/sshd:/sbin/nologin
avahi:x:70:70:Avahi mDNS/DNS-SD Stack:/var/run/avahi-daemon:/sbin/nologin
postfix:x:89:89::/var/spool/postfix:/sbin/nologin
tcpdump:x:72:72::/:/sbin/nologin
gh:x:1000:1000:gh:/home/gh:/bin/bash

root:x:0:0:root:/root:/bin/bash
operator:x:11:0:operator:/root:/sbin/nologin

sed '1,2H;3,4G' 文件名
将1、2行复制到3和4行的下面

[root@gh date]# cat test1.txt
11
26
7
76
99
43
68
678
[root@gh date]# sed '1,2H;3,4G' test1.txt
11
26
7

11
26
76

11
26
99
43
68
678

“112233”将1和3互换位置

[root@gh date]# echo "112233" | sed -r 's/(11)(22)(33)/\3\2\1/'
332211

“112233”将首位字符互换位置

[root@gh date]# echo "112233" | sed -r 's/^(.)(.*)(.)$/\3\2\1/'
312231
posted @ 2022-08-10 19:12  玖拾一  阅读(69)  评论(0编辑  收藏  举报