sed命令篇

运维基础 2018-07-04

sed是一个比awk年龄还要大的命令,全名为stream editor,和awk类似,以程序的方式编辑文本,其最大的优势在于正则匹配能力很强。处理时,把当前处理的行存储在临时缓冲区中,称为“模式空间”(pattern space),接着用sed命令处理缓冲区中的内容,处理完成后,把缓冲区的内容送往屏幕。接着处理下一行,这样不断重复,直到文件末尾。文件内容并没有 改变,除非你使用重定向存储输出。

sed命令(基础篇)

语法形式(基本)

sed [参数] '动作' filename(s)

选项与参数:

-n :使用安静(silent)模式。在一般 sed 的用法中,所有来自 STDIN 的数据一般都会被列出到终端上。但如果加上 -n 参数后,则只有经过sed 特殊处理的那一行(或者动作)才会被列出来。
-e :直接在命令列模式上进行 sed 的动作编辑;
-f :直接将 sed 的动作写在一个文件内, -f filename 则可以运行 filename 内的 sed 动作;
-r :sed 的动作支持的是拓展型正则表达式的语法。(默认是基础正规表达式语法)
-i :直接修改读取的文件内容,而不是输出到终端。

注意其中-i是比较危险的选项,因为它能够直接修改文件内容

动作说明: [n1[,n2]]function
n1, n2 :不见得会存在,一般代表『选择进行动作的行数』,举例来说,如果我的动作是需要在 10 到 20 行之间进行的,则『 10,20[动作行为] 』

function:
a :新增, a 的后面可以接字串,而这些字串会在新的一行出现(目前的下一行)~
c :替换, c 的后面可以接字串,这些字串可以取代 n1,n2 之间的行!
d :删除,因为是删除啊,所以 d 后面通常不接任何参数;
i :插入, i 的后面可以接字串,而这些字串会在新的一行出现(目前的上一行);
p :打印,亦就是将某个选择的数据印出。通常 p 会与参数 sed -n 一起运行~
s :取代,可以直接进行取代的工作,通常这个 s 的动作可以搭配正则表达式!
    例如 1,20s/old/new/g 就是啦!

基本用法

我们首先创建一个名为pets.txt的文本文件,内容如下:

This is my cat
  my cat's name is betty
This is my dog
  my dog's name is frank
This is my fish
  my fish's name is george
This is my goat
  my goat's name is adam

然后使用nl命令辅助输出行号,然后开始使用sed命令

基本示例1:打印pets.txt,删去其中的第3行到第5行

nl pets.txt |sed '3,5d'

输出结果如下:

 1    This is my cat
 2      my cat's name is betty
 6      my fish's name is george
 7    This is my goat
 8      my goat's name is adam

可以看到第3行到第5行的数据被删除

补充:想删除从第3行到最后一行的数据可以使用正则表达式符号$辅助

nl pets.txt |sed '3,$d'

基本示例2:打印pets.txt,并在第二行后添加两行“This is my monkey” 、"my monkey's name is whoami"

使用命令2a添加数据

为了添加多行,需要在每一行结尾处添加反斜杠\,对回车键进行转义

nl pets.txt |sed '2a This is my monkey \

my monkey name is whoami'

最后输出结果如下:

     1    This is my cat
     2      my cat's name is betty
This is my monkey 
 my monkey name is whoami
     3    This is my dog
     4      my dog's name is frank
     5    This is my fish
     6      my fish's name is george
     7    This is my goat
     8      my goat's name is adam

同样,想要在第二行添加相关行,应该使用i

nl pets.txt |sed '2i This is my monkey \

my monkey name is whoami'

基本示例3:打印pets.txt,并将其中的第3,4行替换成两行“I have an apple ,I have a pen”、“Uhh,I have an applepen”

使用3,4c可以对3,4行内容进行替换
换行还是使用反斜杠\进行转义

nl pets.txt |sed '3,4c I have an apple,I have a pen \

Uhh,I have an applepen'

最后输出结果如下:

      1    This is my cat
     2      my cat's name is betty
I have an apple,I have a pen 
Uhh,I have an applepen
     5    This is my fish
     6      my fish's name is george
     7    This is my goat
     8      my goat's name is adam

和基本示例1一样,我们同样可以使用正则表达式符号$表示到最后一行

基本示例4:打印pets.txt,并只打印其中的5到8行

使用5,8p可以输出5到8行

nl pets.txt |sed '5,8p'

输出结果如下:

  1    This is my cat
 2      my cat's name is betty
 3    This is my dog
 4      my dog's name is frank
 5    This is my fish
 5    This is my fish
 6      my fish's name is george
 6      my fish's name is george
 7    This is my goat
 7    This is my goat
 8      my goat's name is adam
 8      my goat's name is adam

发现5到8行被打印了两遍,这不是我们想要的结果

使用参数 -n安静模式,只有经过sed命令处理过的行才打印

nl pets.txt |sed -n '5,8p'

输出结果如下:

 5    This is my fish
 6      my fish's name is george
 7    This is my goat
 8      my goat's name is adam

基本示例5:删除文件的1,2行并保存(谨慎操作)

和awk命令类似,常规使用sed命令是不会改变文件的内容的,但是sed命令还是有一个参数-i,能够直接修改文件内容,所以在使用的时候还是需要小心谨慎,建议使用还是使用vim等文本编辑器对文件内容进行修改

sed -i '1,2d' pets.txt

然后nl pets.txt查看一下

 1    This is my dog
 2      my dog's name is frank
 3    This is my fish
 4      my fish's name is george
 5    This is my goat
 6      my goat's name is adam

原先8行的文件变成了6行

注意使用-i参数时,只能对文件进行操作,不能对由上一个命令传来的结果进行操作,

nl pets.txt |sed -i '1,2d'

即无法使用上面的方式修改并保存pets.txt

sed命令(进阶篇)

正则匹配模式

之前提到了,sed命令强大的地方在于正则匹配,能够很好地将文件内容,提取,组合打印输出,查找与替换甚至还和vi类似,下面详细介绍一下。

我们使用/ /来正则匹配文本内容,然后可以对匹配内容进行操作

正则匹配示例:打印pets.txt的内容,并删除以This开头的行

sed '/^This/d' pets.txt

输出结果如下:

  my cat's name is betty
  my dog's name is frank
  my fish's name is george
  my goat's name is adam

基本替换语法

sed 's/要被替换的内容/替换的内容/g'

正则替换示例1:打印pets.txt的内容,并将my替换成your

nl pets.txt |sed 's/my/your/g'

输出结果如下:

 1    This is your cat
 2      your cat's name is betty
 3    This is your dog
 4      your dog's name is frank
 5    This is your fish
 6      your fish's name is george
 7    This is your goat
 8      your goat's name is adam

既然是正则匹配,那么我们同样可以使用正则表达式的相关符号

^ 表示一行的开头。如:/^#/ 以#开头的匹配。
$ 表示一行的结尾。如:/}$/ 以}结尾的匹配。
\< 表示词首。 如 \<abc 表示以 abc 为首的詞。
\> 表示词尾。 如 abc\> 表示以 abc 結尾的詞。
. 表示任何单个字符。
* 表示某个字符出现了0次或多次。
[ ] 字符集合。 如:[abc]表示匹配a或b或c,还有[a-zA-Z]表示匹配所有的26个字符。如果其中有^表示反,如[^a]表示非a的字符

多点编辑

-e参数允许在同一行里执行多条命令

多点编辑示例:打印pets.txt的内容,并将my替换成your,This 替换成 That

sed -e 's/my/your/g' -e 's/This/That/g'|nl

输出结果如下:

 1    That is your cat
 2      your cat's name is betty
 3    That is your dog
 4      your dog's name is frank
 5    That is your fish
 6      your fish's name is george
 7    That is your goat
 8      your goat's name is adam

正则替换示例2:打印pets.txt的内容,并将每一行的行首添加#

sed 's/^/#/g' pets.txt

输出结果如下:

#This is my cat
#  my cat's name is betty
#This is my dog
#  my dog's name is frank
#This is my fish
#  my fish's name is george
#This is my goat
#  my goat's name is adam

其实就是将开头替换成#号

如果写成

sed 's/^./#/g' pets.txt

输出结果就是将每行的首个字符替换成#号

同样的想要在每一行的结尾添加 ##的话,可使用

sed 's/$/##/g' pets.txt

正则替换示例3:打印pets.txt的内容,并只将3到6行之间的my替换为your

sed '3,6s/my/your/g' pets.txt|nl

输出结果如下:

 1    This is my cat
 2      my cat's name is betty
 3    This is your dog
 4      your dog's name is frank
 5    This is your fish
 6      your fish's name is george
 7    This is my goat
 8      my goat's name is adam

变形一下:打印pets.txt的内容,将每一行的s替换为大写S,且只替换一次

sed 's/s/S/1' pets.txt|nl

最后结果输出如下:

 1    ThiS is my cat
 2      my cat'S name is betty
 3    ThiS is my dog
 4      my dog'S name is frank
 5    ThiS is my fish
 6      my fiSh's name is george
 7    ThiS is my goat
 8      my goat'S name is adam

再变形一下:打印pets.txt的内容,并且只替换每一行第2个及以后的s为大写S

sed 's/s/S/2g' pets.txt

 1    This iS my cat
 2      my cat's name iS betty
 3    This iS my dog
 4      my dog's name iS frank
 5    This iS my fiSh
 6      my fish'S name iS george
 7    This iS my goat
 8      my goat's name iS adam

小结一下:

1.行之间的替换,修改s前面的内容即可,其中s是search查找的意思
2.每一行替换的次数,修改g部分即可,其中g是global全部替换(针对单行)的意思

正则替换示例4:打印pets.txt的内容,将第一到第三行的my替换为your,且将第3行以后的This替换成That

可以使用正则匹配的多点替换功能

sed '1,3s/my/your/g; 3,$s/This/That/g' pets.txt |nl

输出结果如下:

 1    This is your cat
 2      your cat's name is betty
 3    That is your dog
 4      my dog's name is frank
 5    That is my fish
 6      my fish's name is george
 7    That is my goat
 8      my goat's name is adam

同样,也可使用-e指令进行多点编辑

sed -e '1,3s/my/your/g' -e '3,$s/This/That/g' pets.txt |nl

输出结果也是相同的,此处不再赘述

正则替换示例5:打印pets.txt的内容,并将my前后添加中括号,变成[my]

我们可以使用&来当做被匹配的变量,然后可以在基本左右加点东西

sed 's/my/[&]/g' pets.txt|nl

输出结果如下:

This is [my] cat
  [my] cat's name is betty
This is [my] dog
  [my] dog's name is frank
This is [my] fish
  [my] fish's name is george
This is [my] goat
  [my] goat's name is adam

正则替换示例6:打印pets.txt的内容,并将my替换成whoami's

如果使用

sed 's/my/whoami's/g' pets.txt

会报错,因为whoami's自带一个单引号,会和前面的单引号闭合,此时应该使用双引号

sed "s/my/whoami's/g" pets.txt

输出结果如下:

This is whoami's cat
  whoami's cat's name is betty
This is whoami's dog
  whoami's dog's name is frank
This is whoami's fish
  whoami's fish's name is george
This is whoami's goat
  whoami's goat's name is adam

缓冲匹配

我们可以使用N命令:把下一行中的内容纳入缓冲区来进行匹配

使用会把原文本中的偶数行纳入奇数行匹配,而s只匹配并替换一次

缓冲匹配示例:打印pets.txt,将奇数行中的my改成your一次,但是偶数行中的my不变

sed 'N;s/my/your/' pets.txt|nl

记得要去掉g,输出结果如下

 1    This is your cat
 2      my cat's name is betty
 3    This is your dog
 4      my dog's name is frank
 5    This is your fish
 6      my fish's name is george
 7    This is your goat
 8      my goat's name is adam

好的,简单变一下:打印pets.txt,将偶数行中的my改成your一次,但是奇数行中的my不变

使用n命令就可以了,原理类似

sed 'n;s/my/your/' pets.txt

这个有什么用呢?

比如我们可以将奇数行行尾的\n替换为,,就能让偶数行合并到奇数行

sed 'N;s/n/,/' pets.txt|nl

那么输出效果如下:

 1    This is my cat,  my cat's name is betty
 2    This is my dog,  my dog's name is frank
 3    This is my fish,  my fish's name is george
 4    This is my goat,  my goat's name is adam

我们保存一下输出内容,命名为new.txt

圆括号匹配

圆括号括起来的正则表达式所匹配的字符串会可以当成变量来使用,sed中使用的是1,2…,类似于awk命令的$1,$2...

由于在正则模式/ /当中,( )会被当成正则符号,所以可以是用反斜杠\进行转义

我们以new.txt的内容为例

This is my cat,  my cat's name is betty
This is my dog,  my dog's name is frank
This is my fish,  my fish's name is george
This is my goat,  my goat's name is adam

圆括号匹配示例1:打印new.txt的内容,要求输出结果每一行为“动物种类:动物名称”

这个比较有难度,仔细分析一下:

每行提取两个内容:

1.从"This is my "到 ","之间的动物种类

2.从"is "到行尾之间的动物名称

然后还要在两者之间添加冒号:

sed 's/This is my \(.*\),.*is \(.*\)/\1:\2/g' new.txt

输出结果如下:

cat:betty
dog:frank
fish:george
goat:adam

简单解释一下:
对于

This is my cat,  my cat's name is betty

This is my \(.*\),匹配cat,成为变量1,即\1

.*is \(.*\)匹配betty,成为变量2,即为\2

中间添加:,使用\1:\2输出

圆括号匹配示例2:打印ifconfig中各个网卡的ip地址,格式为ip is xxx.xxx.xxx.xxx

首先看一下ifconfig命令的返回结果

eth0      Link encap:Ethernet  HWaddr 00:0C:29:71:D4:FD  
          inet addr:192.168.248.138  Bcast:192.168.248.255  Mask:255.255.255.0
          inet6 addr: fe80::20c:29ff:fe71:d4fd/64 Scope:Link
          UP BROADCAST RUNNING MULTICAST  MTU:1500  Metric:1
          RX packets:58866 errors:0 dropped:0 overruns:0 frame:0
          TX packets:20452 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:1000 
          RX bytes:23498045 (22.4 MiB)  TX bytes:2344509 (2.2 MiB)
          Interrupt:19 Base address:0x2000 

lo        Link encap:Local Loopback  
          inet addr:127.0.0.1  Mask:255.0.0.0
          inet6 addr: ::1/128 Scope:Host
          UP LOOPBACK RUNNING  MTU:65536  Metric:1
          RX packets:1 errors:0 dropped:0 overruns:0 frame:0
          TX packets:1 errors:0 dropped:0 overruns:0 carrier:0
          collisions:0 txqueuelen:0 
          RX bytes:356 (356.0 b)  TX bytes:356 (356.0 b)

发现各个网卡ip特征是

以inet addr:开头,后面是Bcast或Mask

我们先使用

ifconfig|grep "inet addr"

得到

      inet addr:192.168.248.138  Bcast:192.168.248.255  Mask:255.255.255.0
      inet addr:127.0.0.1  Mask:255.0.0.0

然后使用

ifconfig|grep "inet addr"|sed 's/inet addr:\(.*\)  [Bcast|Mask].*$/ip is \1/g'

得到

ip is 192.168.248.138  Bcast:192.168.248.255
ip is 127.0.0.1

因为该正则表达式的逻辑是匹配“inet addr:”与“Bcast”或者“Mask”之间的内容,那么接下来就是提取“ip is ”与“Bcast”之间的内容

ifconfig|grep "inet addr"|sed 's/inet addr:\(.*\)  [Bcast|Mask].*$/ip is \1/g'|sed 's/ip is \(.*\)  Bcast.*/ip is \1/g'

输出结果如下:

      ip is 192.168.248.138
      ip is 127.0.0.1

本文由 古月蓝旻 创作,采用 知识共享署名 3.0,可自由转载、引用,但需署名作者且注明文章出处。

还不快抢沙发

添加新评论