SED 入门

作者: AlgoPeek | 来源:发表于2019-06-23 00:04 被阅读1次

SEDStream EDitor)流编辑器,是Unix下一款文本处理工具。SED 是 Lee E. McMahon 从1973到1974 在贝尔实验室开发的。SED有多种用途,主要用于:

  • 文本替换;
  • 选择性打印文本;
  • 就地编辑文件;
  • 非交互式编辑文件;
  • 其它...;

1.执行流程

SED循环简单执行流程:读取->执行->展示,如下图:


读取:
sed从输入流(文件、标准输入、管道)中读取一行,并将内容存储在pattern buffer中,pattern buffer后边会讲到。

执行:
sed命令会串行地应用于pattern buffer中的内容,默认情况下,这sed命令会应用于第一行,除非指定行地址。后面会说到具体细节。

展示:
将修改后的内容发送到输出流中(标准输出、管道、文件),输出完后,清空缓冲区。

以上步骤会循环执行,直到达到文件末尾。简单地说sed就是从输入流中逐行进行以上三个步骤,理解sed的执行流程对下面的学习至关重要。

2. 学习sed的关键点

  • pattern buffer是sed用于存储输入行的内存区域,sed命令只能作用于pattern buffer,一旦sed命令作用于pattern buffer的结果发送至输出流后,pattern buffer自动被清空;
  • hold buffer也是sed的一块内存区域,但sed命令不能直接作用于hold buffer。所以sed提供了一些命令用于pattern buffer和hold buffer之后进行数据交换,后边会详细讲到;
  • sed初始化时,pattern buffer和hold buffer均为空;
  • 默认情况下,如果未指定行地址,sed将作用于每一行;
  • 如果没有指定输入文件,sed将标准输入作为输入文件;

3. 基本语法

sed [-n] [-e] 'command(s)' files 
sed [-n] -f scriptfile files

先看一个sed实例:

shell> cat books.txt
1) A Storm of Swords, George R. R. Martin, 1216
2) The Two Towers, J. R. R. Tolkien, 352
3) The Alchemist, Paulo Coelho, 197
4) The Fellowship of the Ring, J. R. R. Tolkien, 432
5) The Pilgrimage, Paulo Coelho, 288
6) A Game of Thrones, George R. R. Martin, 864
shell> sed '' book.txt
1) A Storm of Swords, George R. R. Martin, 1216
2) The Two Towers, J. R. R. Tolkien, 352
3) The Alchemist, Paulo Coelho, 197
4) The Fellowship of the Ring, J. R. R. Tolkien, 432
5) The Pilgrimage, Paulo Coelho, 288
6) A Game of Thrones, George R. R. Martin, 864

sed命令可以为空,默认情况下,sed会将读取的每一行输出至标准输出。如果我们指定-n参数,表示关闭默认输出:

shell> sed -n '' books.txt

你会发现上面命令执行后没有任何输出。关闭默认输出后,我们可以通过sed的p命令输出,并且可以指定输出行,如3p表示只输出第三行,如:

shell> sed -n '3p' books.txt
3) The Alchemist, Paulo Coelho, 197

我们可以将命令放到文件中,通过-f参数指定sed命令文件,如:

shell> echo '3p' > commands.txt
shell> sed -n -f commands.txt books.txt
3) The Alchemist, Paulo Coelho, 197

可以使用-e参数拼接多个sed命令,如:

shell> sed -n -e '1p' -e '3p' -e '5p' books.txt
1) A Storm of Swords, George R. R. Martin, 1216
3) The Alchemist, Paulo Coelho, 197
5) The Pilgrimage, Paulo Coelho, 288

使用-i参数表示就地修改文件,这个地方我们先说一下sed的d命令,表示删除(delete),同样可以在前面指定行号,如3d表示删除第三行如:

shell> sed '3d' books.txt
1) A Storm of Swords, George R. R. Martin, 1216
2) The Two Towers, J. R. R. Tolkien, 352
4) The Fellowship of the Ring, J. R. R. Tolkien, 432
5) The Pilgrimage, Paulo Coelho, 288
6) A Game of Thrones, George R. R. Martin, 864

执行完上述命令后,我们打开books.txt,发现文件并没有删除第三行,默认情况下,sed命令只是将结果输出至标准输出,如果指定了-i,就会直接修改源文件:

shell> sed -i '3d' books.txt
shell> cat books.txt
1) A Storm of Swords, George R. R. Martin, 1216
2) The Two Towers, J. R. R. Tolkien, 352
4) The Fellowship of the Ring, J. R. R. Tolkien, 432
5) The Pilgrimage, Paulo Coelho, 288
6) A Game of Thrones, George R. R. Martin, 864

更多sed参数请自行man sed

4. 模式范围

在学习sed命令之前,需要先学习一下模式范围,因为模式范围基本上对所有sed命令是通用的。
前面学习了命令p表示打印至标准输出,并且可以指定行号。如前面说的3p表示打印第3行,打印最后一行,用$表示,

shell> sed -n '$p' books.txt
6) A Game of Thrones, George R. R. Martin, 864

除了指定具体行号外,还可以指定行号范围,中间用分号分隔,如打印2到4行:

shell> sed -n '2,4p' books.txt
2) The Two Towers, J. R. R. Tolkien, 352
3) The Alchemist, Paulo Coelho, 197
4) The Fellowship of the Ring, J. R. R. Tolkien, 432

使用M,+n表示sed会处理M行开始的n行,如2,+2p表示打印从第2行开始的后面2行:

shell> sed -n '2,+2p' books.txt
2) The Two Towers, J. R. R. Tolkien, 352
3) The Alchemist, Paulo Coelho, 197
4) The Fellowship of the Ring, J. R. R. Tolkien, 432

使用M~n表示sed会处理从M行开始的第隔n行,如果1~2p表示打印奇数行:

shell> sed -n '1~2p' books.txt
1) A Storm of Swords, George R. R. Martin, 1216
3) The Alchemist, Paulo Coelho, 197
5) The Pilgrimage, Paulo Coelho, 288

除了指定行号范围外,还可以通过模式匹配行号进行处理,同样以sed命令p为例,打印出现Paulo的行:

shell> sed -n '/Paulo/ p' books.txt
3) The Alchemist, Paulo Coelho, 197
5) The Pilgrimage, Paulo Coelho, 288

也可以将模式匹配跟行号结合使用指定一个范围,如/Paulo/, 4p表示打印匹配到Paulo的行和到第4行:

shell> sed -n '/Paulo/, 4p' books.txt
3) The Alchemist, Paulo Coelho, 197
4) The Fellowship of the Ring, J. R. R. Tolkien, 432
5) The Pilgrimage, Paulo Coelho, 288

也可以使用将模式匹配跟+n组合,表示打印匹配行之后的n行:

shell> sed -n '/Fellowship/, +2p' books.txt
4) The Fellowship of the Ring, J. R. R. Tolkien, 432
5) The Pilgrimage, Paulo Coelho, 288
6) A Game of Thrones, George R. R. Martin, 864

也可以指定模式匹配范围,仍然使用分号分隔,如/Two/, /Fellowship/ p表示打印匹配到Two和匹配到Fellowship中间的行:

shell> sed -n '/Two/, /Fellowship/ p' books.txt
2) The Two Towers, J. R. R. Tolkien, 352
3) The Alchemist, Paulo Coelho, 197
4) The Fellowship of the Ring, J. R. R. Tolkien, 432

5. 正则匹配

由于在sed命令中,正则表达式使用的比较多,但正则表达式有学习成本,可以先学习一下常用的正则表达式,更多正则表达式的知识可以参考Regular expression

正则表达式 说明
^ 匹配行的开始
$ 匹配行的结尾
. 匹配单个字符
[] 匹配字符集,如[abc]匹配字符abc
[^] 非匹配字符集,如[0-9]匹配非数字字符
[-] 匹配字符范围,如[a-z]匹配az的字符
? 匹配0个或1个字符
+ 匹配1个或多个字符
* 匹配0个或多个字符
{n} 匹配出现n次
{n,} 匹配至少出现n次
{n,m} 匹配出现n到m次
| 选择,如str(1|2|3)匹配str1,str2,str3
() 分组

有了正则表达式基础,再来看下sed的
sed基本命令替换命令s,其语法如下:

[address1[,address2]]s/pattern/replacement/[flags]

如果我们想替换books.txt文件中第一行中的MartinBrown:

shell> sed -n '1 s/Martin/Brown/p' books.txt
1) A Storm of Swords, George R. R. Brown, 1216

使用i 标记可以忽略大小写进行匹配:

shell> sed  -n 's/pAuLo CoElHo/PAULO COELHO/pi' books.txt
3) The Alchemist, PAULO COELHO, 197 
5) The Pilgrimage, PAULO COELHO, 288

再来看下分组匹配:

shell>echo "Three One Two" | sed 's/\(\w\+\) \(\w\+\) \(\w\+\)/\2 \3 \1/'
One Two Three

上面命令通过\w\+匹配单词进行分组,通过\1 \2 \3索引分组,索引顺序按照分组顺序,然后再分组重排列进行输出。

6. 基本命令

6.1 d命令

d命令前面提到了,为删除命令,前面可以指定地址范围,地址范围格式参考模式范围,d命令语法如下:

[address1[,address2]]d 

删除books.txt文件中的2到4行,如下:

shell> sed '2,4d' books.txt
1) A Storm of Swords, George R. R. Martin, 1216
5) The Pilgrimage, Paulo Coelho, 288
6) A Game of Thrones, George R. R. Martin, 864

6.2 w命令

w为写(write)命令,表示将匹配的地址写入到指定文件中,地址格式参考模式范围,w命令语法如下:

[address1[,address2]]w file 

books.txt的2到4行写入到文件tmp.txt

shell> sed -n '2,4w tmp.txt' books.txt
shell> cat tmp.txt
2) The Two Towers, J. R. R. Tolkien, 352
3) The Alchemist, Paulo Coelho, 197
4) The Fellowship of the Ring, J. R. R. Tolkien, 432

6.3 r命令

r为读(read)命令,表示将从指定文件中读取内容到指定地址中,地址格式参考模式范围,r命令语法如下:

[address]r file

将文件junk.txt的内容写入到books.txt的第3行后面,如下:

shell> cat junk.txt
This is junk text.
shell> sed '3 r junk.txt' books.txt
1) A Storm of Swords, George R. R. Martin, 1216
2) The Two Towers, J. R. R. Tolkien, 352
3) The Alchemist, Paulo Coelho, 197
This is junk text.
4) The Fellowship of the Ring, J. R. R. Tolkien, 432
5) The Pilgrimage, Paulo Coelho, 288
6) A Game of Thrones, George R. R. Martin, 864

6.4 a命令

a为追回(append)命令,表示将指定的内容追回到指定地址中,地址格式参考模式范围,a命令语法如下:

[address]a Append text

books.txt文件的第4行追回内容7) Adultry, Paulo Coelho, 234' books.txt,如下:

shell> sed '4 a 7) Adultry, Paulo Coelho, 234' books.txt 
1) A Storm of Swords, George R. R. Martin, 1216
2) The Two Towers, J. R. R. Tolkien, 352
3) The Alchemist, Paulo Coelho, 197
4) The Fellowship of the Ring, J. R. R. Tolkien, 432
7) Adultry, Paulo Coelho, 234
5) The Pilgrimage, Paulo Coelho, 288
6) A Game of Thrones, George R. R. Martin, 864

6.5 i命令

i为插入(insert)命令,表示将指定内容播放到指定地址中,地址格式参考模式范围,i命令语法如下:

[address]i Insert text 

books.txt文件的第4行插入内容7) Adultry, Paulo Coelho, 234' books.txt,如下:

shell> sed '4 i 7) Adultry, Paulo Coelho, 234' books.txt 
1) A Storm of Swords, George R. R. Martin, 1216
2) The Two Towers, J. R. R. Tolkien, 352
3) The Alchemist, Paulo Coelho, 197
7) Adultry, Paulo Coelho, 234
4) The Fellowship of the Ring, J. R. R. Tolkien, 432
5) The Pilgrimage, Paulo Coelho, 288
6) A Game of Thrones, George R. R. Martin, 864

6.6 c命令

c为修改(change)命令,表示在指定地址中替换指定内容,地址格式参考模式范围,c命令语法如下:

[address1[,address2]]c Replace text

将文件books.txt的第3行替换为3) Adultry, Paulo Coelho, 324,如下:

shell> sed '3 c 3) Adultry, Paulo Coelho, 324' books.txt
1) A Storm of Swords, George R. R. Martin, 1216
2) The Two Towers, J. R. R. Tolkien, 352
3) Adultry, Paulo Coelho, 324
4) The Fellowship of the Ring, J. R. R. Tolkien, 432
5) The Pilgrimage, Paulo Coelho, 288
6) A Game of Thrones, George R. R. Martin, 864

6.7 y命令

y为转换命令,有点类似于tr命令,即将一组字符转换成另一组字符,语法格式如下:

[address1[,address2]]y/list-1/list-2/

将数字0123456789映射为xabcdefghi,如下:

shell> echo '1122345690' | sed 'y/0123456789/xabcdefghi'
aabbcdefix

6.8 n命令

n为读取下一行(next)命令,n命令经常用于连接其它命令,看下面示例:

sed command1
sed command2
n
sed command3
sed command4

sed在读取一行后,将读取行存入到pattern buffer中,然后分别将sed command1sed command2作用于pattern buffer中的内容,到执行n的时候,sed会读取下一行到pattern buffer中,然后分别将sed command3sed command4作用于pattern buffer中的内容(下一行的内容)。请务必理解n命令的工作方式,下面例子是打印books.txt文件中偶数行的内容:

shell> sed -n 'n;p' books.txt
2) The Two Towers, J. R. R. Tolkien, 352
4) The Fellowship of the Ring, J. R. R. Tolkien, 432
6) A Game of Thrones, George R. R. Martin, 864

sed首先读取第一行,然后执行n命令时,按照n命令的工作方式,n读取下一行(也就是第二行),将其内容放到pattern buffer中,然后执行p命令,将pattern buffer中的内容输出。依次执行文件后续行,直到文件到达结尾。

6.9 N命令

n命令不同的是,N命令是将读取的下一行的内容添加换行符(\n)后追加到pattern buffer中,如:

shell> sed -n 'N;s/\n/;/g;p' books.txt
1) A Storm of Swords, George R. R. Martin, 1216 ; 2) The Two Towers, J. R. R. Tolkien, 352
3) The Alchemist, Paulo Coelho, 197; 4) The Fellowship of the Ring, J. R. R. Tolkien, 432
5) The Pilgrimage, Paulo Coelho, 288 ; 6) A Game of Thrones, George R. R. Martin, 864

以上命令的工作方式是:
首先sed读取第一行,存和pattern buffer中,然后执行N命令,按照N命令的工作方式,先是添加一个换行符,然后再将下一行(第二行)的内容一并追加至pattern buffer中,然后我们执行s/\n/;/g将换行符替换为;,最后输出。

6.10 P命令

P命令也是打印,和p命令不同的,P命令只是打印N命令换行符前面的内容,如:

shell> sed -n 'N;P' books.txt
1) A Storm of Swords, George R. R. Martin, 1216
3) The Alchemist, Paulo Coelho, 197
5) The Pilgrimage, Paulo Coelho, 288

如果没有N命令,P命令等同于p命令。

6.11 e命令

e为执行(execute)命令,sed可以执行外部命令,并将执行结果插入到指定地址前面,其语法如下:

[address1[,address2]]e [command]

如将命令date的结果插入文件books.txt的第3行,如下:

shell> sed '3 e date' books.txt
1) A Storm of Swords, George R. R. Martin, 1216
2) The Two Towers, J. R. R. Tolkien, 352
Sat Jun 22 23:42:12 CST 2019
3) The Alchemist, Paulo Coelho, 197
4) The Fellowship of the Ring, J. R. R. Tolkien, 432
5) The Pilgrimage, Paulo Coelho, 288
6) A Game of Thrones, George R. R. Martin, 864

6.12 q命令

q为退出(quit)命令,表示退出本次执行流程,其语法如下:

[address]q [value]

其中value中退出返回码,如:

shell> sed '2 q 100' books.txt
1) A Storm of Swords, George R. R. Martin, 1216
2) The Two Towers, J. R. R. Tolkien, 352
shell> echo $?
100

模式管理

最后我们讲一下模式管理,也是sed的一些高级用法。前面提到了hold buffer,但我们从来没有用过,前面我们已经知道,sed命令只能作用于pattern buffer
不能作用于hold buffer,所以sed提供了以下命令,供pattern buffer和hold buffer之间进行数据交换,如下:

命令 说明
h 将pattern buffer中的内容拷贝至hold buffer中,hold buffer中的内容会被覆盖
H 将pattern buffer中的内容追回到hold buffer中
g 将hold buffer中的内容拷贝至pattern buffer中,pattern buffer中的内容会被覆盖
G 将hold buffer中的内容追回至pattern buffer中
x 交换pattern buffer和hold buffer之间内容

如何使用呢,下面例子是将文件books.txt中的内容逆置:

shell> sed -n '1!G;h;$!d;p' books.txt
6) A Game of Thrones, George R. R. Martin, 864
5) The Pilgrimage, Paulo Coelho, 288
4) The Fellowship of the Ring, J. R. R. Tolkien, 432
3) The Alchemist, Paulo Coelho, 197
2) The Two Towers, J. R. R. Tolkien, 352
1) A Storm of Swords, George R. R. Martin, 1216

来看一下执行步骤:

  1. sed首先读取一行,对一行来讲,就是1) A Storm of Swords, George R. R. Martin, 1216,并将其存储在pattern buffer中,
  2. 1!G:该命令表示除第一行外,将hold buffer中的内容追回到pattern buffer中。
  3. h:该命令会将pattern buffer中的内容copy至hold buffer中;
  4. $1d:该命令表示除了最后一行,将删除pattern buffer中的内容;

通过以上步骤的解析我们可以知道,其工作原理有点像单链表逆置。即除第一行外,将hold buffer中的内容追回到pattern buffer中,然后再将pattern buffer中的内容存储到hold buffer中,循环执行直到最后一次。对于第一轮循环,如果不是最后一行,则删除pattern buffer中的内容;对于输出操作,由于除最后一次外,pattern buffer中的内容都被清空,所以最终输出为执行最后一行的时候pattern buffer中的内容。

7. 参考

[1] https://en.wikipedia.org/wiki/Sed
[2] https://www.tutorialspoint.com/sed/index.htm
[3] https://coolshell.cn/articles/9104.html

相关文章

网友评论

    本文标题:SED 入门

    本文链接:https://www.haomeiwen.com/subject/coehqctx.html