首发于 Linux

你所不知道的那些sed命令

sed 全名 stream editor,一般用于文本内容替换。本文介绍日常工作中常用到的 sed 命令,更加完整的说明可以点击文末阅读原文参考 sed 手册。

01—模式空间(pattern space)

  • 将文件以 为单位读取到内存(模式空间)
  • 使用 sed 的 每个脚本 对该行进行操作
  • 处理完成后输出该行

如下所示,读取 a.log 文件第一行内容,sed 中有 2 个替换脚本,第一个将 aa 替换成 @@ ,第二个将 bb 替换成 !! ,最后输出结果。

meng➜/tmp» cat a.log     
aa bb cc
meng➜/tmp» sed 's/aa/@@/;s/bb/!!/' a.log   
@@ !! cc

02—替换命令 s

字符串替换,将文件中 src 字符串替换成 new,支持多个替换脚本

sed ’s/src/new/‘ filename
sed -e ’s/src/new/’ -e ’s/src1/new1/‘ filename
# 这里等同于下面分号隔开
sed 's/src/new/;s/src1/new1/' filename

默认只会输出替换后的文本, -i 可以直接将源文件修改掉。

sed -i 's/src/new/' filename

正则替换:最常用的替换方式,需要你对正则表达式比较熟悉。

sed ’s/正则表达式/new/‘ filename
sed -r ’s/扩展正则表达式/new/ filenam
# 每行前面添加 #
sed 's/^/#/' filename

扩展正则表达式包括 ?, +, |, ( ) 这几个字符

在扩展正则表达式中,使用圆括号匹配的内容可以当做变量来使用。比如我们可以将 aa 字符前加两个 !!

meng➜/tmp» sed -r 's/(aa)/!!\1/' a.log  
!!aa bb c

03—标志位

s/src/new/标志位 `` - g:每次出现都替换。 - 数字:替换第几次出现,可以数字+g 替换第几次之后。 - p:打印模式空间内容

默认每行只会替换匹配的第一个,我们可以通过 g 来替换所有

meng➜/tmp» cat b.log   
aa aa aa aa
meng➜/tmp» sed 's/aa/@@/g' b.log
@@ @@ @@ @@
meng➜/tmp» sed 's/aa/@@/2' b.log 
aa @@ aa aa
meng➜/tmp» sed 's/aa/@@/2g' b.log
aa @@ @@ @@

p 将匹配的内容进行再次打印。加 p 后匹配的内容会被打印两次,第一次是标准输出,第二次是模式空间内容输出。这个可以结合 -n 使用,-n 表示处理完不进行标准输出。比如:在测试命令的时候,文件行数非常多,我只关心命令生效的内容。

meng➜/tmp» cat c.log 
aa aa aa aa
bb bb
meng➜/tmp» sed 's/aa/@@/p' c.log   
@@ aa aa aa
@@ aa aa aa
bb bb
meng➜/tmp» sed -n 's/aa/@@/p' c.log 
@@ aa aa aa

04—寻址

sed 默认对每行进行操作,增加寻址后仅对匹配的行进行操作。

  • /正则表达式/s/src/new/g。
  • 行号s/old/new/g。行号可以是具体的行,也可以是最后一行 $ 符合。
  • 可以使用两个寻址符号,也可以混合使用行号和正则。
  • /正则表达式/{ s/src/new;s/src/new/ },多个替换命令。
meng➜/tmp» cat d.log   
aa aa
11 aa
cc aa
meng➜/tmp» sed '/^[a-z]/s/aa/@@/' d.log 
@@ aa
11 aa
cc @@
meng➜/tmp» sed '2s/aa/@@/' d.log  
aa aa
11 @@
cc aa
meng➜/tmp» sed '2,3s/aa/@@/' d.log  
aa aa
11 @@
cc @@
meng➜/tmp» sed '/^[a-z]/,$s/aa/@@/' d.log  
@@ aa
11 @@
cc @@

/^[a-z]/,$s/ 从 /^[a-z]/ 匹配的行开始,一直到最后一行

05—其他

d 删除匹配的行

meng➜/tmp» sed '/11/d' d.log 
aa aa
cc aa

a 追加

# 在匹配的行后追加字符串 hello
meng➜/tmp» sed '/11/a hello' d.log 
aa aa
11 aa
hello
cc aa

i 插入

meng➜/tmp» sed '/11/i hello' d.log 
aa aa
hello
11 aa
cc aa

c 更改

# 相当于直接替换掉这一行
meng➜/tmp» sed '/11/c hello' d.log 
aa aa
hello
cc aa

p 打印

# 打印长度为 6 的回文串
meng➜/tmp» sed -rn '/(.)(.)(.)\3\2\1/p' word.log   
redder

06—多行匹配

有了 N 、P 、D 我们就可以多行内容一起处理了。

  • N 将下一行加入到模式空间。
  • D 删除模式空间中的第一个字符到第一个换行符。
  • P 打印模式空间中的第一个字符到第一个换行符。
meng➜/tmp» cat e.log  
# 将第二行合并到第一行,然后将换行符删掉
meng➜/tmp» sed 'N;s/\n//' e.log     
hello

接下来看个示例,hello meng 被换行分隔成了多行,将它合并成一行,并替换成 hello sed。

meng➜/tmp» cat f.log  
o meng hel
lo meng
# 处理流程见下图
meng➜/tmp» sed 'N;s/\n//;s/meng/sed\n/;P;D' f.log   
hello sed
 hello sed

07—保持空间(hold space)

保持空间也是一块暂存区域,我们可以将模式空间的内容复制到保持空间,也可以将保持空间内容复制到模式空间,方便我们对多行进行操作。

  • h 和 H 将模式空间的内容存放到保持空间,小写是覆盖模式,大写是追加模式。
  • g 和 G 将保持空间的内容取出到模式空间,大小写含义同上。
  • x 交换模式空间和保持空间内容。

保持空间默认有一个初始字符:换行符

看个示例,tac 命令是将文件倒序输出,用 sed 怎么实现呢?

➜  /tmp cat g.log