sed流编辑器

“sed是用于过滤和转换文本的流编辑器。”

概述

sed,全称为stream editor,是一个非交互式的编辑器。

sed命令是利用script来处理文本文件。sed可依照script的指令,来处理、编辑文本文件。

sed主要用来自动编辑一个或多个文件;简化对文件的反复操作;编写转换程序等。

sed基本知识点

sed工作流程

sed

前提:待操作文本是由至上而下的一行或N行组成。

  • 基本工作流程:

    • 当用sed命令对文本进行处理的时候,sed先读取对象的文本文件的第一行到模式空间中。
    • 当有内容进入模式空间时,sed的编辑命令对模式空间中的内容进行编辑操作(修改,替换,删除,追加,显示等等)
    • 模式空间中的内容编辑处理完成之后,sed把此内容通过标准输出(默认为显示器)打印出来,并删除模式空间中的内容。
    • 第一行处理结束。从新读取第二行的内容进行处理,直到最后一行。

注意:持有空间可以和模式空间的内容进行互相追加、覆盖等操作。

sed命令执行位置

几乎所有的sed命令都可以添加[address[,address]]来确定命令执行的位置,完整指令如下:

1
2
3
4
5
6
# !表示匹配成功后是否执行命令
[address[,address]][!]{cmd}
# 删除非第二行至尾行,即删除第一行
echo "a\naa\naab\naaab\naaabb\naaabbb" | sed "2,$ ! d"
# 删除第二行至尾行
echo "a\naa\naab\naaab\naaabb\naaabbb" | sed "2,$ d"

address

命令执行位置可以使用相对位置:

1
2
3
4
5
# 匹配a并输出a和其后连续两行,+2表示其后连续两行
echo "a\nb\nc\nd\ne\nf" | sed -n "/a/,+2 p"
# 匹配a并输出其后连续两行
echo "a\nb\nc\nd\ne\nf" | sed -n "/a/,+2{//n;p}"
echo "a\nb\nc\nd\ne\nf" | sed -n "/a/,+2{/a/n;p}"

relative address

sed命令打包

sed命令可以用大括号进行分组作为嵌套命令,表示外层命令执行完成后,再执行内层命令:

1
2
3
4
5
6
# 对3行到第4行,执行命令/I am/d
sed '3,4 {/I am/d}' test
# 对1行到第4行,匹配/I am/成功后,再匹配/dog/,成功后执行d命令
sed '3,6 {/I am/{/dog/d}}' test
# 从第一行到最后一行,如果匹配到空格,则去除空格
sed '1,${s/ *//g}' test

group

持有空间

持有空间(Hold Space),可以存放模式空间中的内容,也可以取出内容追加或覆盖到模式空间中。

常用命令参数如下:

参数 说明
g hold space中的内容拷贝到pattern space中,原来pattern space里的内容清除
G hold space中的内容appendpattern space
h pattern space中的内容拷贝到hold space中,原来的hold space里的内容被清除
H pattern space中的内容appendhold space
x 交换pattern spacehold space的内容

示例如下:

1
2
3
4
# 将模式空间内容追加到持有空间中
echo "one\ntwo\nthree" | sed "H;g"
# 若只想看到结果,使用以下命令
echo "one\ntwo\nthree" | sed -n "H;p"

hold1

具体过程如下:

hold1 proc

1
2
# 将文件进行反序
echo "one\ntwo\nthree" | sed '1!G;h;$!d'

hold2

其中的 ‘1!G;h;$!d’ 可拆解为三个命令:

  • 1!G —— 只有第一行不执行G命令,将hold space中的内容append回到pattern space
  • h —— 每一行都执行h命令,将pattern space中的内容拷贝到hold space中
  • $!d —— 除了最后一行不执行d命令,其它行都执行d命令,删除当前行

具体过程如下:

hold2 proc

sed命令

常用参数介绍

sed命令的语法为:sed [参数]... [执行命令] [输入文件]...

1
sed -i "1s/Hello/World/" test

basic

常用参数如下:

参数 说明
-n 安静模式,只打印受影响的行,默认打印输入数据的全部内容
-e script 用于在脚本中添加多个执行命令一次执行,在命令行中执行多个命令通常不需要加该参数
-f filename 指定执行filename文件中的命令
-r 使用扩展正则表达式,默认为标准正则表达式
-i 将直接修改输入文件内容,而不是打印到标准输出设备

sed编辑器的执行命令

sed的执行命令格式如下:

1
2
[n1][,n2]command
[n1][~step]command
1
2
3
# 具体命令如下:
sed -n '2,5p' test # 打印25
sed -n '1~2p' test # 打印奇数行

n

其中n1n2表示输入内容的行号,它们之间为,逗号则表示从n1n2行,如果为波浪号则表示从n1开始以step为步进的所有行;command为执行动作,下面为一些常用动作指令:

命令 说明
s 行内替换
c 整行替换
a 插入到指定行的后面
i 插入到指定行的前面
p 打印指定行,通常与-n参数配合使用
d 删除指定行
g 一行上替换所有匹配

操作实例

  • 打印指定行
1
2
sed -n '1,6p' test # 打印16
sed -n '2~2p' test # 打印偶数行

n2

  • 行内替换
1
2
# 将所有wen替换为hi
sed -n "s/wen/hi/gp" test

replace

  • 行间替换
1
2
# 将第五行替换为wonderful
sed "5c\wonderful" test

line

  • 行首插入字符
1
2
# 在每行头部插入#+空格
sed 's/^/# /g' test

head

  • 行尾插入字符
1
2
# 在每行行末插入空格+!
sed 's/$/ !/g' test

tail

  • 行间插入字符
1
2
3
4
5
6
# 在第一行之前插入hello
echo "a\naa\naab\naaab\naaabb\naaabbb" | sed "1 i hello"
# 在第一行之后插入hello
echo "a\naa\naab\naaab\naaabb\naaabbb" | sed "1 a hello"
# 在匹配到的aaa之后插入hello
echo "a\naa\naab\naaab\naaabb\naaabbb" | sed "/aaa/a hello"

aandi

  • 指定替换内容

将数字n放在脚本头部表示匹配第n行:

1
2
3
4
5
6
# 替换第3行的所有a
echo "a\naa\naaa\naaaa\naaaaa\naaaaaa\n" | sed "3s/a/A/g"
# 替换第36行的所有a
echo "a\naa\naaa\naaaa\naaaaa\naaaaaa\n" | sed "3,6s/a/A/g"
# 替换奇数行的所有a
echo "a\naa\naaa\naaaa\naaaaa\naaaaaa\n" | sed "1~2s/a/A/g"

number head

将数字n放在脚本尾部表示匹配每行的第n个字符:

1
2
3
4
5
6
# 替换每一行的第2个s
echo "a\naa\naaa\naaaa\naaaaa\naaaaaa\n" | sed "s/a/A/1"
# 替换每一行的第3个s
echo "a\naa\naaa\naaaa\naaaaa\naaaaaa\n" | sed "s/a/A/3"
# 替换每一行的第2个之后s
echo "a\naa\naaa\naaaa\naaaaa\naaaaaa\n" | sed "s/a/A/g2"

number tail

  • 多个匹配

如果需要一次性匹配多个模式,可使用命令:

1
2
3
echo "a\naa\naaa\naaaa\naaaaa\naaaaaa" | sed "1,3 s/a/A/g; 4,$ s/a/B/g"
# 上面的命令等价于:
echo "a\naa\naaa\naaaa\naaaaa\naaaaaa" | sed -e "1,3 s/a/A/g" -e "4,$ s/a/B/g"

multi

注意: 4,$ s/A/B/g两个命令之间是有空格的。

  • 使用匹配的变量
1
2
3
4
# 每个aaa都用中括号圈起来
echo "a\naa\naaa\naaaa\naaaaa\naaaaaa" | sed "s/aaa/[&]/g"
# 复制每一个a
echo "a\naa\naaa\naaaa\naaaaa\naaaaaa" | sed "s/a/&&/g"

variable

  • 圆括号匹配
1
2
# 匹配到aaa+任意字符串则将整个字符串划分为aa:a+任意字符串,\1表示匹配第一个括号的内容,\2同理
echo "a\naa\naab\naaab\naaabb\naaabbb" | sed "s/\(aa\)\(a.*\)/\1:\2/g"

bracket

  • 删除行
1
2
3
4
5
6
# 删除匹配aa的行
echo "a\naa\naab\naaab\naaabb\naaabbb" | sed "/aa/d"
# 删除第二行
echo "a\naa\naab\naaab\naaabb\naaabbb" | sed "2d"
# 删除第二行到尾行
echo "a\naa\naab\naaab\naaabb\naaabbb" | sed "2,$ d"

delete

sed的命令还有很多丰富的使用方法,可以参见官方手册