本文主要是总结下 sed 的一些常规用法,主要参考酷壳的这篇文章“sed简明教程”,还有 sed 的官方手册。sed 是 stream editor 的缩写,也即是流编辑器,将输入流按照命令做相应的编辑变换的工作。本文主要是作为学习 sed 的一个总结,帮助记忆,挂一漏万是难免的了。

sed命令的格式一般如下:

sed [命令参数]  [脚本]  [输入流(如文件名)]

如下,就是将文件 my.txt 中的第1到3行所有 my 替换为 your,第3行到文件尾的 This 替换为 That,并最后将替换后结果写回文件 my.txt 中。

$ sed -i '1,3s/my/your/g; 3,$s/This/That/g' my.txt

命令参数

几个常用的选项有:

-i 直接编辑原文件
-n 安静模式,不输出

脚本部分

脚本部分用单引号或双引号包围,内部可以分为多个命令,用分号隔开,如下:

命令块1;命令块2;...;命令块n

其中每个命令块的格式如下:

[匹配范围][!][sed命令 [命令参数]]

匹配范围

可以指定单行或者指定一个范围,可以直接写行号,如指定第1行 "1",或者从第3行到文件尾 "3,$";还可以通过形式 "/pattern/" 来指定找到该模式的行,如 "/dog/,/cat/" 代表从含有单词 dog 的行开始,到其后第一个含有单词 cat 的行结束,如果没有找到含有 dog 的行则后面的命令不被执行,如果有开始但是没有找到含有 cat 的行则命令会从开始行执行到文件尾。匹配范围还可以指定相对行数,如 "/dog/,+3" 表示的范围是第一个含有 dog 的行及其后3行。

如果匹配范围省略则命令对输入流的所有行都执行。

sed 命令

在 sed 命令前加上感叹号代表在指定的匹配范围内不执行该命令,其他行则执行。

a 命令,即在找到的行后 append 后面的内容,如下就是将第2到第5行每行后都加入一行“---***---”

$ sed "2,5a ---***---" my.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

i 命令,与 a 命令类似即在找到的行前 insert 进后面的内容。
c 命令,即将找到的行替换为后面的内容,如下,就将第2到第5行替换为“---***---”

$ sed "2,5c ---***---" my.txt
This is my cat
---***---
my fish's name is george
This is my goat
my goat's name is adam

d 命令,即将找到的行 delete。
p 命令,即将找到的行 print 出来。
N 命令,把下一行的内容纳入缓冲区做匹配。
s 命令,这个应该是最重要也是最常用的命令,substitute 替换,一般的使用格式如下:

s/pattern-source/pattern-destination/pattern-flag

其主要就是将匹配到的 pattern-source 的内容替换为 pattern-destination 的内容,如果熟悉 vim 的就会发现此处和 vim 中的s替换是一致的,也使用正则表达式匹配,也一样可以使用圆括号匹配。pattern-flag 可以使用 "/g" 代表所有能匹配上的都进行替换 globally,如果不加此则每行只替换第一个匹配上的模式,还可以使用 "/I" 代表匹配不区分大小写 Ignore Case。下面是关于 s 命令的一些例子。

$ cat my.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/s/S/2" my.txt  #只替换每一行的第2个s
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 "N;s/This is my \([^\n]*\)\n.*is \(.*\)/\1:\2/g" my.txt
cat:betty
dog:frank
fish:george
goat:adam

进阶部分

这一部分主要是关于 pattern space 和 hold space 的,酷壳的文章中有很好的图例解释,sed 手册里关于这两个概念是这样解释的:

sed 保持有两个数据缓存:当前的 pattern space 和辅助用的 hold space。初始都为空。

sed 对输入的每一行都执行如下的循环,首先,sed 读入一行,并把它放入 pattern space 中,执行命令。命令执行完后,若不是有指定 "-n" 参数则将当前的 pattern space 的内容输出到输出流中,至此完成了关于输入流中一行的循环。

关于这两个数据缓存有几个相关的命令:

  • g: 将hold space中的内容拷贝到pattern space中,原来pattern space里的内容清除
  • G: 将hold space中的内容append到pattern space\n后
  • h: 将pattern space中的内容拷贝到hold space中,原来的hold space里的内容被清除
  • H: 将pattern space中的内容append到hold space\n后
  • x: 交换pattern space和hold space的内容

几个例子:

$ cat t.txt
one
two
three
$ sed 'H;g' t.txt

one

one
two

one
two
three
$ sed '1!G;h;$!d' t.txt # 反序一个文件的行
three
two
one

Leave a Reply

Your email address will not be published.

Post Navigation