首页 > 代码库 > sed用法

sed用法

1. sed概述


    sed是Stream EDitor的缩写,意为流式文本编辑器。sed名字来源于其功能,可以想象污水流经污水处理点后流出更为干净的水,sed也一样,文本中的数据流可以使用sed这个文本处理工具中各种编辑命令进行处理,最终以另一种格式输出。


    sed是一种‘非交互式‘的编辑器,一次只处理一行内容。在处理时,会先将待处理的一行暂存至内存中的某一段缓存空间,这段缓存空间称为“模式空间(Pattern Space)”。接着使用sed命令处理模式空间中的内容,而处理后的内容默认输出至标准输出,默认不修改原文件。然后接着处理下一行,直至最后一行。sed常用来重复编辑一个或多个文件,简化对文件的操作。

    

    此外,除了"模式空间(Pattern Space)",sed在使用一些高级命令(例如:g/G, h/H, x)时还会使用到保持空间(Hold Space),保持空间用于保存模式空间的内容,但不管模式空间和保持空间如何工作,最终只能由模式空间输出至标准输出。


技术分享


技术分享

2. sed处理流程

当我们指定用sed命令去处理某个文件时,其处理流程如下:

① 读入新的一行进入模式空间(pattern space);
② 从指定的操作指令中取出第一条指令,判断该行是否被pattern匹配;
③ 如果不匹配,则忽略后续的编辑指令,在静默模式下不会输出,否则默认输出;
④ 如果匹配,并针对缓存的行执行后续的编辑命令。执行后,返回第2步继续取出下一条指令。
⑤ 当应用所有指令后,将模式空间中缓存的处理结果输出;返回第1步读取文本的下一行;
⑥ 当所有行都处理之后,结束。

 技术分享


   总结一下,sed的处理是这样的:把要处理的一行放进模式空间中,先看看是否要默认输出这一行至标准输出;接着对模式空间匹配到的行进行处理(执行一个或一个以上的编辑命令);最后再把模式空间中匹配到的行的处理结果输出至标准输出。

 

3. sed命令使用


命令格式:

sed [option]... ‘script‘ [FILE]...
sed 选项 ‘地址定界编辑命令‘ 文件


常用选项:

    -n:静默模式,抑制默认输出;

    -r:支持使用扩展正则表达式元字符;、

    -i:直接修改原文件;

    -i.bak:直接修改原文件,但会生成一个原文件的备份文件(后缀名为.bak)

    -e:用于实现多个‘script‘一次执行;

    -f /PATH/TO/SED_SCRIPT_FILE:可使用sed脚本文件来执行对文本的处理操作。


地址定界:

(1)不接地址:全局应用于每一行,即匹配所有行;

(2)单地址:

N:第N行;

/pattern/:由pattern匹配到的行;

$:最后一行;

(3)地址范围:

M,N:从第M行到第N行之间的所有行;

M,+N:从第M行开始到M+N之间的所有行;

N,$:从第N行到最后一行之间的所有行;

M,/pattern/:从第M行到由pattern第一次匹配到的行之间的所有行;

/pattern1/,/pattern2/:从由pattern1第一次匹配到的行到由pattern2第一次匹配到的行之间的所有行;

(4)步进表示法:

1~2:所有奇数行;例如: sed ‘1~2p‘ test

2~2:所有偶数行;例如: sed ‘2~2p‘ test


编辑命令:

编辑命令是对模式空间中匹配到的行进行编辑处理操作。编辑命令有基本命令和高级命令,基本命令一次只能处理一行,而高级命令可实现一次处理多行(或理解为将多行视为一行来处理)。

(a)基本命令:
    d:delete, 删除模式空间中匹配到的行;
    p:print, 显示模式空间中被匹配到的行;
    a \TEXT:append, 在指定行后追加文本TEXT,支持使用\n实现多行追加;
    i \TEXT:insert, 在指定行前插入文本TEXT,支持使用\n实现多行插入;
    c \TEXT:将指定行的内容替换为文本TEXT;
    w /PATH/TO/SOMEFILE:write, 保存模式空间中匹配到的行至指定的文件中;
    r /PATH/FROM/SOMEFILE:read, 将指定文件的内容读取至当前模式空间中被匹配到的行后面,
    常用于实现文件合并;
    s/pattern/replaces/:查找替换;分隔符可自行指定,常用的分隔符有/, #, @等;
        替换标记:
            g:全局替换;
            w /PATH/TO/SOMEFILE:将替换的结果保存至指定文件中;
            p:显示替换成功的行;
    y:用于(对应)转换字符;
    =:打印行号;
    !:条件取反;即对不被模式匹配到的行执行编辑命令;格式为:地址定界!编辑命令
    l:打印行号,并显示控制字符;
    q:读取匹配到的行后退出;
    
    
(b)高级命令:
    n:覆盖读取匹配到的行的下一行至模式空间中;
    N:追加读取匹配到的行的下一行至模式空间中,并用\n连接两行;
    D:删除模式空间的第一行的内容,并在模式空间中继续执行编辑命令;
    P:打印模式空间的第一行的内容;
    h:hold, 将模式空间中的内容覆盖至保持空间中;
    H:Hold, 将模式空间中的内容追加至保持空间中;
    g:get, 将保持空间中的内容覆盖至模式空间中;
    G:Get, 将保持空间中的内容追加至模式空间中;
    x:exchange, 将模式空间中的内容与保持空间中的内容互换;
    
    
注意:
(1) sed保持空间(Hold Space):用于保存模式空间的内容;
(2) h, H, g, G, x这5个高级命令会使用到sed的保持空间;


4. sed使用示例

4.1. 以行为单位新增/删除


将/etc/passwd的内容输出并且打印行号,同时在第1行之前插入两行文本,第一行内容为"How are you?",第二行内容为"How old are you?":

[root@localhost ~]# nl /etc/passwd | sed ‘1i \How are you?\nHow old are you?‘
How are you?
How old are you?
1    root:x:0:0:root:/root:/bin/bash
2    bin:x:1:1:bin:/bin:/sbin/nologin
3    daemon:x:2:2:daemon:/sbin:/sbin/nologin
4    adm:x:3:4:adm:/var/adm:/sbin/nologin
.....(后面省略).....


命令解释:
可使用\n以实现多行插入文本。


在/etc/passwd第2行之后追加文本"Drink tea?":

[root@localhost ~]# nl /etc/passwd | sed ‘2a \Drink tea?‘
1    root:x:0:0:root:/root:/bin/bash
2    bin:x:1:1:bin:/bin:/sbin/nologin
Drink tea?
3    daemon:x:2:2:daemon:/sbin:/sbin/nologin
4    adm:x:3:4:adm:/var/adm:/sbin/nologin
5    lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
.....(后面省略).....


删除/etc/passwd第2行至第5行内容:

[root@localhost ~]# nl /etc/passwd | sed ‘2,5d‘
1    root:x:0:0:root:/root:/bin/bash
6    sync:x:5:0:sync:/sbin:/bin/sync
7    shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown
8    halt:x:7:0:halt:/sbin:/sbin/halt
9    mail:x:8:12:mail:/var/spool/mail:/sbin/nologin
1    0operator:x:11:0:operator:/root:/sbin/nologin
.....(后面省略).....


命令解释:
因为在模式空间中,第2行~第5行中每一行会被匹配到,而d命令会删除在模式空间中匹配到的行,
因此这几行不输出。


删除/etc/passwd中除了第一行之外的所有行:

[root@localhost ~]# nl /etc/passwd | sed ‘1!d‘
1    root:x:0:0:root:/root:/bin/bash


把文本第一行之后的空白行删除:

待处理的test文本内容如下:
[root@localhost ~]# cat test
aaaaaa
bbb
cc
d
e
[root@localhost ~]# 
[root@localhost ~]# sed ‘1{n;d}‘ test
aaaaaa
bbb
cc
d
e
[root@localhost ~]# 


命令解释:
因为地址匹配的是第一行,所以两个指令是针对第一行来进行处理的;当第一行读进来后,因为第
一行符合匹配条件,所以会对第一行执行处理命令,首先执行的是n命令,即覆盖追加第二行至第一
行中,在此之前第一行会默认输出至屏幕,而后在模式空间中的第一行被文本中的第二行覆盖,接
着再执行d命令,即把模式空间中的第一行(即文本的第二行删除)。接着再读取文本的第三行,不满
足匹配条件,因此不执行命令并默认输出,接着读取文本的第四行......

注意:对某一行执行多次处理可用{}将处理命令command括起来,花括号内的每个命令之间用分号分
隔。


4.2. 以行为单位的替换与打印


将/etc/passwd第三行替换为文本"This is the third line.":

[root@localhost ~]# nl /etc/passwd | sed ‘3c \This is the third line.‘
1    root:x:0:0:root:/root:/bin/bash
2    bin:x:1:1:bin:/bin:/sbin/nologin
This is the third line.
4    adm:x:3:4:adm:/var/adm:/sbin/nologin
5    lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
6    sync:x:5:0:sync:/sbin:/bin/sync
7    shutdown:x:6:0:shutdown:/sbin:/sbin/shutdown
8    halt:x:7:0:halt:/sbin:/sbin/halt
.....(后面省略).....


使用编辑命令y实现对应转换字符:

待处理的test文本内容如下:
[root@localhost ~]# cat test
a
b
c
d
aa
abc
[root@localhost ~]# 

将字符a、b、c分别替换为x、y、z:
[root@localhost ~]# sed ‘y/abc/xyz/‘ test
x
y
z
d
xx
xyz
[root@localhost ~]#


命令解释:
因为没有接地址,因此是匹配全局;


用sed显示/etc/passwd的行号:

[root@localhost ~]# sed ‘=‘ /etc/passwd
1
root:x:0:0:root:/root:/bin/bash
2
bin:x:1:1:bin:/bin:/sbin/nologin
3
daemon:x:2:2:daemon:/sbin:/sbin/nologin
4
adm:x:3:4:adm:/var/adm:/sbin/nologin
5
lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
6
sync:x:5:0:sync:/sbin:/bin/sync
.....(后面省略).....


命令解释:
每个行号占用一行,显示行号,再显示行的内容。


只读/etc/passwd的前10行:

[root@localhost ~]# sed ‘10q‘ /etc/passwd
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 -n ‘1,10p‘ /etc/passwd,那么当文本文件非常大甚至有几百万行时,根据sed工作流
程,它会处理每一行,即便我们需要的仅是显示前10行,这是非常浪费CPU资源的,因此可使用q命
令,指定sed处理完前10行即退出。


4.3. 数据的查找替换


搜索/etc/passwd中root用户对应的一行,将‘bash‘改为‘blueshell‘,再输出该行:

[root@localhost ~]# sed -n ‘/^root/{s/bash/blueshell/;p}‘ /etc/passwd
root:x:0:0:root:/root:/bin/blueshell

如果替换好该行的bash为blueshell后就退出,则:

[root@localhost ~]# sed ‘/^root/{s/bash/blueshell/;q}‘ /etc/passwd
root:x:0:0:root:/root:/bin/blueshell

在两个数字之间添加‘:‘:

待处理的test文本内容如下:
[root@localhost ~]# cat test
123
321
添加‘:‘:
[root@localhost ~]# sed -r ‘s/([0-9])([0-9])([0-9])/\1:\2:\3/‘ test
1:2:3
3:2:1


只用sed命令完成对"ifconfig ens33"命令执行结果的处理,要求输出为网卡ens33的IP地址:

先尝试匹配‘inet‘:
[root@localhost ~]# ifconfig ens33 | sed -n ‘/inet/p‘ 
inet 10.10.10.140  netmask 255.255.255.0  broadcast 10.10.10.255
inet6 fe80::20c:29ff:fec8:ff4e  prefixlen 64  scopeid 0x20<link>

再过滤掉inet6这一行:
[root@localhost ~]# ifconfig ens33 | sed -n ‘/inet\>/p‘ 
inet 10.10.10.140  netmask 255.255.255.0  broadcast 10.10.10.255
或者:
[root@localhost ~]# ifconfig ens33 | sed -n ‘/inet\b/p‘ 
inet 10.10.10.140  netmask 255.255.255.0  broadcast 10.10.10.255

接着删除IP前面的部分:
[root@localhost ~]# ifconfig ens33 | sed -n ‘/inet\>/p‘ | sed ‘s/^.*inet //‘
10.10.10.140  netmask 255.255.255.0  broadcast 10.10.10.255

再删除IP后面的部分,得到最终结果:
[root@localhost ~]# ifconfig ens33 | sed -n ‘/inet\>/p‘ | sed ‘s/^.*inet //‘ | sed ‘s/
 netmask.*$//‘
10.10.10.140


命令解释:
使用sed对列进行处理时,通常使用搜索替换s/pattern/replaces/,常使用的替换标记是g;不过  
sed在对列的处理上不如awk。


将/etc/passwd第1到第5行中shell为/bin/bash的用户的shell改为‘/bin/greenshell‘,再输出:

[root@localhost ~]# sed -n ‘1,5{s@/bin/bash@/bin/greenshell@;p}‘ /etc/passwd
root:x:0:0:root:/root:/bin/greenshell
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
或者:
[root@localhost ~]# sed -n ‘1,5{s/\/bin\/bash/\/bin\/greenshell/;p}‘ /etc/passwd
root:x:0:0:root:/root:/bin/greenshell
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


命令解释:
当分隔符出现在模式或替换文本中时,需要进行转义;或者使用其他的分隔符,例如:s@@@, s###,
 s%%%, ...


4.4. 高级命令的使用


把文本的前两行拼接成一行,中间用空格隔开:

待处理的test文本内容如下:
[root@localhost ~]# cat test
this is a
boy
c
d
e

拼接前两行,中间用空格隔开:
[root@localhost ~]# sed ‘1{N;s/\n/ /}‘ test
this is a boy
c
d
e


命令解释:
处理时,把第一行读取进模式空间中,而第一行能够被匹配,因此针对第一行执行花括号内的操作
:先追加读取第二行至模式空间中,第一行与第二行用\n连接;接着执行搜索替换,将‘\n‘替换为
空格,这样就实现拼接了。接着读取文本的第三行至模式空间中,因为不被匹配,因此不执行编辑
命令,在非静默模式下会直接输出模式空间的内容,因此直接输出‘c‘;接着读取第四行......


如果出现空白行只保留一个空白行,即删除多余的空白行,行与行之间最多只能有一个空白行:

待处理的test文本内容如下:
[root@localhost ~]# cat test
a
b
c
d
[root@localhost ~]# 

删除多余的空白行:
[root@localhost ~]# sed ‘/^$/{N;/\n$/D}‘ test
a
b
c
d


解决思路:
首先用/^$/去匹配空白行,针对被匹配到的空白行执行编辑命令;接着可用命令N追加下一行至匹配
到的空白行之后,且用\n连接,这时可根据模式空间中的第二行(在这里是\n之后的内容)是否为空
,去判断空白行是否只有一行;如果\n后为非空字符串(例如b),则说明模式空间中只有一个空白行
;如果\n为空,则不止一个空白行,此时模式空间为:[]\n[],[]代表空白行;这时可使用命令D删
除模式空间中的第一行的内容(在这里第一行的内容为[])。

用同样的思路解释如下命令的执行结果:
[root@localhost ~]# sed ‘/^$/{N;/\n$/d}‘ test
a
b
c
d


显示以下文本中‘a‘的上一行的内容:

待处理的test文本内容如下:
[root@localhost ~]# cat test
1
a
2
b
3
c
4
a
c

要求只显示a上一行的内容:
[root@localhost ~]# sed -n ‘N;/a$/P‘ test
1
4


解决思路:
读取一行进模式空间后,先追加下一行进来,判断是否是以‘\na‘结束,因此可用‘a$‘来作为追加下
一行后的匹配条件;如果是以‘\na‘结束,则打印上一行;如果不是以‘\na‘结束,则使用静默模式
不输出。


命令解释:
第一行读取进模式空间时,先追加文本第二行进来,两者在模式空间中以\n连接,接着看看模式空
间中的内容是否满足模式/a$/的匹配条件;因为匹配,所以输出上一行,而加上-n选项抑制默认输
出,因此只输出一个‘1‘;接着开始读取下一行‘2‘进入模式空间中,接着追加下一行‘b‘进来,模式
空间中的内容为:2\nb;因为不匹配,所以在静默模式下不输出模式空间中的内容;接着读取下一
行进模式空间中,再追加一行,此时模式空间的内容为:3\nc;......再读取、追加,模式空间的
内容为:4\na;符合匹配,输出‘4‘;读取下一行,不再追加,且不符合匹配,在静默模式下不输出
。


尝试其他方法:
[root@localhost ~]# sed ‘N;/a$/P;D‘ test
1
4
c


分析:
处理时,先把第一行放进模式空间中,追加下一行,模式空间内容为:1\na,因此符合条件,打印
模式空间中的第一行1;接着删除模式空间中的第一行1;然后追加读取下一行2,此时模式空间内容
为a\n2,不符合匹配条件,因此不打印模式空间第一行,而删除模式空间中的第一行内容;再追加
,模式空间内容为:2\nb;......当模式空间内容剩下:a\nc时,因为不符合匹配条件,不打印模
式空间中的第一行,而删除模式空间中的第一行,最后模式空间只剩下c,因为不是静默模式,所以
默认输出c,故有此结果。


尝试:
[root@localhost ~]# sed ‘N;/a$/P;d‘ test
1
4
c


分析:
处理时,先把第一行放进模式空间中,追加下一行,模式空间内容为:1\na,因此符合条件,打印
模式空间中的第一行1;接着删除模式空间中的行;然后读取文本的下一行‘2‘进入模式空间,追加
一行‘b‘,此时模式空间中的内容为:2\nb,不符合匹配条件/a$/,直接执行d命令删除模式空间中
匹配到的行(此时匹配条件为全局);......最后模式空间中只剩下‘c‘,在不是静默模式的情况下默
认输出。


要想把刚才的结果的最后一行‘c‘删除掉,可尝试:
[root@localhost ~]# sed ‘$!N;/a$/P;D‘ test
1
4
符合要求;

[root@localhost ~]# sed ‘$!N;/a$/P;d‘ test
1
4
同样符合要求;

但若将test文本改为这样:
[root@localhost ~]# cat test
1
a
2
b
3
c
4
a
a
即把最后一行改为‘a‘。

这时再次执行上述命令:
[root@localhost ~]# sed ‘$!N;/a$/P;d‘ test
1
4
a
符合要求;

[root@localhost ~]# sed ‘$!N;/a$/P;D‘ test
1
4
a
a
不符合要求;


分析:
当输出4时,模式空间内容为:a,因为此时本行‘a‘不是文本的最后一行,所以会追加文本的下一行
(文本最后一行)至模式空间中,此时模式空间内容变为:a\na,符合匹配条件,打印模式空间的上
一行,而后删除模式空间的第一行‘a‘,此时模式空间只剩下‘a‘,因为没有加-n选项所以默认输出
此时模式空间中剩下的内容‘a‘。


命令解释:
很多情况下,N、P、D这三个命令都是可以结合使用的,P命令都是用在N命令之后、D命令之前的。
这三个命令结合起来可形成一个输入输出的循环,并且每次只打印一行:读入一行后,N命令继续读
下一行,P命令打印第一行,D命令删除第一行,执行完成后回到最开始重复该过程。


在文本的每一行之后都添加一行空白行:

待处理的test文本内容如下:
[root@localhost ~]# cat test
a
b
c
d
e
[root@localhost ~]# 

使用命令G添加空白行:
[root@localhost ~]# sed ‘G‘ test
a
b
c
d
e
[root@localhost ~]# 


命令解释:
命令G是将保持空间中的内容追加至模式空间中,而保持空间中的内容为空白,在追加后原有模式空
间中的内容多了:\n [];其中[]表示空白行。


将文本全部换为空白行:

待处理的test文本内容如下:
[root@localhost ~]# cat test
a
b
c
d
e
[root@localhost ~]# 

使用命令G:
[root@localhost ~]# sed ‘g‘ test
[root@localhost ~]# 


命令解释:
命令g是将保持空间中的内容覆盖至模式空间中,而保持空间默认为空。


命令H、x的使用:

待处理的test文本内容如下:
[root@localhost ~]# cat test
a
b
c
d
e
[root@localhost ~]# 

执行H命令:
[root@localhost ~]# sed ‘H;$x‘ test
a
b
c
d
a
b
c
d
e
[root@localhost ~]# 


命令解释:
命令H是将模式空间中的内容追加至保持空间中;在读取文本最后一行‘e‘进入模式空间后,先追加
至保持空间中,而后因为符合匹配条件(最后一行‘$‘),因此执行x命令,即将模式空间中的内容与
保持空间中的内容互换,而保持空间此时的内容为:[] \n a \n b \n c \n d \n e,因此得到以上
执行结果。


4.5. sed 保持空间-综合示例

技术分享

使用逗号拼接行:
[root@localhost ~]# sed ‘H;$!d;${x;s/^\n//;s/\n/,/g}‘ test
1,2,3,4


5. sed与vim,awk,grep的比较



    总的来说,相对于vim这种强大的“交互式”文本编辑器而言,sed的优势在于可以重复对文本的行进行处理,通常在对很多匹配到的行执行多条编辑命令时,这种优势体现更为明显,而如果用vim进行“交互式”处理时,则相当耗费时间,并且操作简单重复且繁琐枯燥。



    sed与awk,grep这三种工具作为Linux文本处理三剑客,各有各自的优势,谁也替代不了谁。只是相比较而言,sed与awk功能更加强大,已独立成一种语言。grep在实现过滤文本时效率要比其他工具高得多sed作为流编辑器在对文本进行处理时功能非常强大,默认不会修改原文件;sed虽然有过滤功能,但实现起来效率低不如grep;而sed在对列的处理能力上相比awk要差得多,awk也是一种文本处理语言,在Linux上的实现为gawk(GNU awk),它把文本看成数据库,将文本分成许多段,然后分别对这些段进行处理或格式化后输出,且不修改原文件;awk是报告生成器,可格式化生成文本,因此非常适于生成具有一定格式的报告文本。


    grep, sed, awk这几个工具在生产环境中经常搭配使用,结合文本查找工具find,可实现快速查找、过滤、处理文本的功能。


本文出自 “Tab” 博客,请务必保留此出处http://xuweitao.blog.51cto.com/11761672/1897752

sed用法