介绍

sed编辑器被称作流编辑器(stream editor),和普通的交互式文本编辑器恰好相反。在交互式 文本编辑器中(比如vim),你可以用键盘命令来交互式地插入、删除或替换数据中的文本。流编辑器则会在编辑器处理数据之前基于预先提供的一组规则来编辑数据流。

sed编辑器可以根据命令来处理数据流中的数据,这些命令要么从命令行中输入,要么存储 在一个命令文本文件中。sed编辑器会执行下列操作。

  1. 一次从输入中读取一行数据。
  2. 根据所提供的编辑器命令匹配数据。
  3. 按照命令修改流中的数据。
  4. 将新的数据输出到STDOUT。

在流编辑器将所有命令与一行数据匹配完毕后,它会读取下一行数据并重复这个过程。在流 编辑器处理完流中的所有数据行后,它就会终止。 由于命令是按顺序逐行给出的,sed编辑器只需对数据流进行一遍处理就可以完成编辑操作。

这使得sed编辑器要比交互式编辑器快得多,你可以快速完成对数据的自动修改。

sed命令的格式如下。

sed options script file 

选项允许你修改sed命令的行为.

script参数指定了应用于流数据上的单个命令。如果需要用多个命令,要么使用-e选项在 命令行中指定,要么使用-f选项在单独的文件中指定。有大量的命令可用来处理数据。

使用方式

1. 在命令行定义编辑器命令

默认情况下,sed编辑器会将指定的命令应用到STDIN输入流上。这样你可以直接将数据通 过管道输入sed编辑器处理。这里有个简单的示例。

$ echo "This is a test" | sed 's/test/big test/' 
This is a big test
$

这个例子在sed编辑器中使用了s命令。s命令会用斜线间指定的第二个文本字符串来替换第 一个文本字符串模式。在本例中是big test替换了test。

在运行这个例子时,结果应该立即就会显示出来。这就是使用sed编辑器的强大之处。你可 以同时对数据做出多处修改,而所消耗的时间却只够一些交互式编辑器启动而已。

重要的是,要记住,sed编辑器并不会修改文本文件的数据。它只会将修改后的数据发送到 STDOUT。如果你查看原来的文本文件,它仍然保留着原始数据。

2. 在命令行使用多个编辑器命令

sed -e 's/brown/green/; s/dog/cat/' data1.txt

两个命令都作用到文件中的每行数据上。命令之间必须用分号隔开,并且在命令末尾和分号 之间不能有空格。

如果不想用分号,也可以用bash shell中的次提示符来分隔命令。只要输入第一个单引号标示出sed程序脚本的起始(sed编辑器命令列表),bash会继续提示你输入更多命令,直到输入了标示 结束的单引号。

1
2
3
4
5
$sed -e '
> s/brown/green/
> s/fox/elephant/
> s/dog/cat/' data1.txt
$

必须记住,要在封尾单引号所在行结束命令。bash shell一旦发现了封尾的单引号,就会执行 命令。开始后,sed命令就会将你指定的每条命令应用到文本文件中的每一行上。

3. 从文件中读取编辑器命令

如果有大量要处理的sed命令,那么将它们放进一个单独的文件中通常会更方便一些。 可以在sed命令中用-f选项来指定文件。

1
2
3
4
5
6
$ cat script1.sed 
s/brown/green/ 
s/fox/elephant/ 
s/dog/cat/
$
$ sed -f script1.sed data1.txt

在这种情况下,不用在每条命令后面放一个分号。sed编辑器知道每行都是一条单独的命令。 跟在命令行输入命令一样,sed编辑器会从指定文件中读取命令,并将它们应用到数据文件中的 每一行上。

我们很容易就会把sed编辑器脚本文件与bash shell脚本文件搞混。为了避免这种情况,可 以使用.sed作为sed脚本文件的扩展名。

替换选项

用s命令(substitute)来在行中替换文本.这个命令还有另外一些选 项能让事情变得更为简单。

1. 替换标记

替换命令在替换多行中的文本时能正常工作,但默认情况下它只替换每行中出现的第一处。 要让替换命令能够替换一行中不同地方出现的文本必须使用替换标记(substitution flag)。替换标 记会在替换命令字符串之后设置。

s/pattern/replacement/flags

有4种可用的替换标记:

  1. 数字,表明新文本将替换第几处模式匹配的地方;
  2. g,表明新文本将会替换所有匹配的文本;
  3. p,表明原先行的内容要打印出来;
  4. w file,将替换的结果写到文件中。

在第一类替换中,可以指定sed编辑器用新文本替换第几处模式匹配的地方。将替换标记指定为2的结果就是:sed编辑器只替换每行中第二次出现的匹配模式。

g替换标 记使你能替换文本中匹配模式所匹配的每处地方。

p替换标记会打印与替换命令中指定的模式匹配的行。这通常会和sed的-n选项一起使用。

-n选项将禁止sed编辑器输出。但p替换标记会输出修改过的行。将二者配合使用的效果就是 只输出被替换命令修改过的行。

w替换标记会产生同样的输出,不过会将输出保存到指定文件中。sed编辑器的正常输出是在STDOUT中,而只有那些包含匹配模式的行才会保存在指定的输出 文件中。

2. 替换字符

有时你会在文本字符串中遇到一些不太方便在替换模式中使用的字符。Linux中一个常见的 例子就是正斜线(/)。

替换文件中的路径名会比较麻烦。比如,如果想用C shell替换/etc/passwd文件中的bash shell,必须这么做:

$ sed 's/\/bin\/bash/\/bin\/csh/' /etc/passwd

由于正斜线通常用作字符串分隔符,因而如果它出现在了模式文本中的话,必须用反斜线来转义。

要解决这个问题,sed编辑器允许选择其他字符来作为替换命令中的字符串分隔符:

sed 's!/bin/bash!/bin/csh!' /etc/passwd

使用地址

默认情况下,在sed编辑器中使用的命令会作用于文本数据的所有行。如果只想将命令作用 于特定行或某些行,则必须用行寻址(line addressing)。

在sed编辑器中有两种形式的行寻址:

  1. 以数字形式表示行区间
  2. 用文本模式来过滤出行

两种形式都使用相同的格式来指定地址:

[address]command 

也可以将特定地址的多个命令分组:

address {
   command1
	command2
	command3 
}

sed编辑器会将指定的每条命令作用到匹配指定地址的行上。

1. 数字方式的行寻址

当使用数字方式的行寻址时,可以用行在文本流中的行位置来引用。sed编辑器会将文本流 中的第一行编号为1,然后继续按顺序为接下来的行分配行号。

在命令中指定的地址可以是单个行号,或是用起始行号、逗号以及结尾行号指定的一定区间 范围内的行。这里有个sed命令作用到指定行号的例子。

$ sed '2s/dog/cat/' data1.txt

sed编辑器只修改地址指定的第二行的文本。这里有另一个例子,这次使用了行地址区间。

$ sed '2,3s/dog/cat/' data1.txt

如果想将命令作用到文本中从某行开始的所有行,可以用特殊地址——美元符。

$ sed '2,$s/dog/cat/' data1.txt

2. 使用文本模式过滤器

sed编辑器允许指定文本模式来过 滤出命令要作用的行。格式如下:

/pattern/command 

必须用正斜线将要指定的pattern封起来。sed编辑器会将该命令作用到包含指定文本模式的行上。

如果你想只修改用户Samantha的默认shell,可以使用sed命令。

$ sed '/Samantha/s/bash/csh/' /etc/passwd

该命令只作用到匹配文本模式的行上。虽然使用固定文本模式能帮你过滤出特定的值,就跟 上面这个用户名的例子一样,但其作用难免有限。sed编辑器在文本模式中采用了一种称为正则表达式(regular expression)的特性来帮助你创建匹配效果更好的模式。

3. 命令组合

如果需要在单行上执行多条命令,可以用花括号将多条命令组合在一起。sed编辑器会处理 地址行处列出的每条命令。

$ sed '2{
> s/fox/elephant/
> s/dog/cat/
> }' data1.txt

两条命令都会作用到该地址上。当然,也可以在一组命令前指定一个地址区间。

删除行

文本替换命令不是sed编辑器唯一的命令。如果需要删除文本流中的特定行,可以用删除 命令。

删除命令d名副其实,它会删除匹配指定寻址模式的所有行。使用该命令时要特别小心,如 果你忘记加入寻址模式的话,流中的所有文本行都会被删除。

sed 'd' data1.txt

当和指定地址一起使用时,删除命令显然能发挥出最大的功用。可以从数据流中删除特定的 文本行,通过行号指定:

sed '3d' data6.txt

或者通过特定行区间指定:

sed '2,3d' data6.txt

或者通过特殊的文件结尾字符:

sed '3,$d' data6.txt

sed编辑器的模式匹配特性也适用于删除命令。sed编辑器会删掉包含匹配指定模式的行。

sed '/number 1/d' data6.txt

记住,sed编辑器不会修改原始文件。你删除的行只是从sed编辑器的输出中消失了。原始文件仍然包含那些“删掉的”行。

也可以使用两个文本模式来删除某个区间内的行,但这么做时要小心。你指定的第一个模式 会“打开”行删除功能,第二个模式会“关闭”行删除功能。sed编辑器会删除两个指定行之间 的所有行(包括指定的行)。如果找到开始模式但没匹配到结束模式,开始模式之后的所有数据流就都被删掉了。

sed '/1/,/3/d' data6.txt

插入和附加文本

sed编辑器允许向数据流插入和附加文本行。两个操作的区别可能比较让人费解:

  1. 插入(insert)命令(i)会在指定行前增加一个新行;
  2. 附加(append)命令(a)会在指定行后增加一个新行。

new line中的文本将会出现在sed编辑器输出中你指定的位置。

sed '[address]command\new line'

记住,当使用插入命令时,文本会出现在数据流文本的前面。

echo "Test Line 2" | sed 'i\Test Line 1'

当使用附加命令时,文本会出现在数据流文本的后面。

$ echo "Test Line 2" | sed 'a\Test Line 1'

在命令行界面提示符上使用sed编辑器时,你会看到次提示符来提醒输入新的行数据。你必 须在该行完成sed编辑器命令。一旦你输入了结尾的单引号,bash shell就会执行该命令。

1
2
3
4
5
$ echo "Test Line 2" | sed 'i\ 
> Test Line 1'
Test Line 1
Test Line 2
$

这样能够给数据流中的文本前面或后面添加文本,但如果要向数据流内部添加文本呢?

要向数据流行内部插入或附加数据,你必须用寻址来告诉sed编辑器你想让数据出现在什么 位置。可以在用这些命令时只指定一个行地址。可以匹配一个数字行号或文本模式,但不能用地 址区间。这合乎逻辑,因为你只能将文本插入或附加到单个行的前面或后面,而不是行区间的前 面或后面。

下面的例子是将一个新行插入到数据流第三行前。

$ sed '3i\
> This is an inserted line.' data6.txt

下面的例子是将一个新行附加到数据流中第三行后。

$ sed '3a\
> This is an appended line.' data6.txt

修改行

修改(change)命令允许修改数据流中整行文本的内容。它跟插入和附加命令的工作机制一样,你必须在sed命令中单独指定新行。

$ sed '3c\
> This is a changed line of text.' data6.txt

在这个例子中,sed编辑器会修改第三行中的文本。也可以用文本模式来寻址。

$ sed '/number 3/c\
> This is a changed line of text.' data6.txt

文本模式修改命令会修改它匹配的数据流中的任意文本行。

你可以在修改命令中使用地址区间,sed编辑器会用这一行文本来替换数据流中的两行文本,而不是逐一修改这两行文本。

$ sed '2,3c\
> This is a new line of text.' data6.txt

转换命令

转换(transform)命令(y)是唯一可以处理单个字符的sed编辑器命令。转换命令格式 如下。

[address]y/inchars/outchars/

转换命令会对inchars和outchars值进行一对一的映射。inchars中的第一个字符会被转 换为outchars中的第一个字符,第二个字符会被转换成outchars中的第二个字符。这个映射过程会一直持续到处理完指定字符。如果inchars和outchars的长度不同,则sed编辑器会产生一 条错误消息。

$ sed 'y/123/789/' data8.txt

inchars模式中指定字符的每个实例都会被替换成outchars模式中 相同位置的那个字符。

转换命令是一个全局命令,也就是说,它会文本行中找到的所有指定字符自动进行转换,而 不会考虑它们出现的位置

打印

1. 打印行

跟替换命令中的p标记类似,p命令可以打印sed编辑器输出中的一行。如果只用这个命令,也没什么特别的。

$ echo "this is a test" | sed 'p'

它所做的就是打印已有的数据文本。打印命令最常见的用法是打印包含匹配文本模式的行。

$ sed -n '/number 3/p' data6.txt

在命令行上用-n选项,你可以禁止输出其他行,只打印包含匹配文本模式的行。

也可以用它来快速打印数据流中的某些行。

$ sed -n '2,3p' data6.txt

如果需要在修改之前查看行,也可以使用打印命令,比如与替换或修改命令一起使用。可以创建一个脚本在修改行之前显示该行。

$ sed -n '/3/{
>p
> s/line/test/p
> }' data6.txt

sed编辑器命令会查找包含数字3的行,然后执行两条命令。首先,脚本用p命令来打印出原 始行;然后它用s命令替换文本,并用p标记打印出替换结果。输出同时显示了原来的行文本和新 的行文本。

2. 打印行号

等号命令会打印行在数据流中的当前行号。行号由数据流中的换行符决定。每次数据流中出 现一个换行符,sed编辑器会认为一行文本结束了。

$ sed '=' data1.txt

sed编辑器在实际的文本行出现前打印了行号。如果你要在数据流中查找特定文本模式的话, 等号命令用起来非常方便。

$ sed -n '/number 4/{ 
>=
>p
> }' data6.txt

3. 列出行

列出(list)命令(l)可以打印数据流中的文本和不可打印的ASCII字符。任何不可打印 字符要么在其八进制值前加一个反斜线,要么使用标准C风格的命名法(用于常见的不可打印字符),比如\t,来代表制表符。

$ sed -n 'l' data9.txt

制表符的位置使用\t来显示。行尾的美元符表示换行符。如果数据流包含了转义字符,列出命令会在必要时候用八进制码来显示。

使用sed处理文件

写入文件

w命令用来向文件写入行。该命令的格式如下:

[address]w filename 

filename可以使用相对路径或绝对路径,但不管是哪种,运行sed编辑器的用户都必须有文件的写权限。地址可以是sed中支持的任意类型的寻址方式,例如单个行号、文本模式、行区间 或文本模式。

$ sed '1,2w test.txt' data6.txt

从文件读取数据

读取(read)命令(r)允许你将一个独立文件中的数据插入到数据流中。

读取命令的格式如下:

[address]r filename 

filename参数指定了数据文件的绝对路径或相对路径。你在读取命令中使用地址区间,只 能指定单独一个行号或文本模式地址。sed编辑器会将文件中的文本插入到指定地址后

$ sed '3r data12.txt' data6.txt

sed编辑器会将数据文件中的所有文本行都插入到数据流中。同样的方法在使用文本模式地 址时也适用。

$ sed '/number 2/r data12.txt' data6.txt

如果你要在数据流的末尾添加文本,只需用美元符地址符就行了。

读取命令的另一个很酷的用法是和删除命令配合使用:利用另一个文件中的数据来替换文件中的占位文本。

要在占位文本后插入名单,只需读取 命令就行了。但这样的话,占位文本仍然会留在输出中。要删除占位文本的话,你可以用删除命令。

$ sed '/LIST/{
> r data11.txt
>d
> }' notice.std