sed编辑器基础

知识点扫盲

sed——流编辑器(stream editor),它在处理数据之前基于预先提供的一组规则来编辑数据流。
sed编辑器根据命令来处理数据流中的数据,这些命令可以来自命令行,也可以存储到文件中。
sed编辑器处理数据流时,会执行以下操作:

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

sed命令的格式:
sed options script file
options选项:

  • -e script: 在处理输入时,将script中指定的命令添加到已有的命令中;
  • -f file:在处理输入时,将file中指定的命令添加到已有的命令中;
  • -n : 不产生命令输出,使用print命令完成打印输出;

基础命令

在命令行定义编辑器命令

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

这个例子中使用了s命令,s命令会用指定分隔符使用第二个文本字符串替换第一个文本字符串。例子中使用real test 替换了 test
sed编辑器的强大之处在于结果会立即显示出来。你可以同时对数据做出多处修改,但消耗的时间只够一些交互式编辑器启动而已。

$ cat sedData1.txt
The quick brown fox jumps over the lazy dog.
The quick brown fox jumps over the lazy dog.
The quick brown fox jumps over the lazy dog.
The quick brown fox jumps over the lazy dog.
$ sed 's/dog/cat/' sedData1.txt
The quick brown fox jumps over the lazy cat.
The quick brown fox jumps over the lazy cat.
The quick brown fox jumps over the lazy cat.
The quick brown fox jumps over the lazy cat.

可以很明显的看到,sed命令几乎瞬间就执行完并返回数据,在处理每行数据的同时,结果也显示出来了。
这里需要明确的是, sed并不会修改文件的数据,它只是将修改后的数据发送到STDOUT。

在命令行使用多个编辑命令

要在sed命令行上执行多个命令时,只要使用-e选项就可以了。

$ sed -e 's/brown/green/; s/dog/cat/' sedData1.txt
The quick green fox jumps over the lazy cat.
The quick green fox jumps over the lazy cat.
The quick green fox jumps over the lazy cat.
The quick green fox jumps over the lazy cat.

执行的两个命令都作用到每行数据上,命令之间必须用分号隔开,并且命令末尾和分号之间不能有空格
如果不想用分号,也可以使用bash shell中的次提示符分隔命令。

$ sed -e '
quote> s/brown/green/
quote> s/dog/cat/
quote> ' sedData1.txt
The quick green fox jumps over the lazy cat.
The quick green fox jumps over the lazy cat.
The quick green fox jumps over the lazy cat.
The quick green fox jumps over the lazy cat.

一定不要忘了,要在封尾单引号所在行结束命令,bash shell一旦发现了封尾的单引号,就会执行命令。

从文件中读取编辑器命令

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

$ cat script1.sed
s/brown/green/
s/fox/elephant/
s/dog/cat/
$
$ sed -f script1.sed sedData1.txt
The quick green elephant jumps over the lazy cat.
The quick green elephant jumps over the lazy cat.
The quick green elephant jumps over the lazy cat.
The quick green elephant jumps over the lazy cat.

在这种情况下,不用在每个命令后添加分号,因为sed编辑器知道每行都是一条独立的命令。

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

可以集成到脚本中的基本命令和功能

更多的替换选项

我们上面已经掌握了如何用s命令(substitute)在行中替换文本,这个命令还有其他选项让处理文本变得更简单。
替换标记
s命令的替换标记在替换命令字符串之后设置 s/pattern/replacement/flags,有四种可用的替换标记:

  • 数字,表明新文本将替换第几处模式匹配到的地方;
  • g,表明新文本将替换所有匹配到的文本;
  • p,表明原先行的内容要打印出来;
  • w file,将替换的结果写到文件中。
$ cat test1.txt
This is a test line of the test script.
This is the second test line of the test script.
$
$ sed 's/test/trial/2' test1.txt
This is a test line of the trial script.
This is the second test line of the trial script.
$
$ sed 's/test/trial/g' test1.txt
This is a trial line of the trial script.
This is the second trial line of the trial script.
$ 
$ cat test2.txt
This is a test line.
This is a different line.
$
$ sed -n 's/test/trial/p' test2.txt
This is a trial line.
$
$ sed 's/test/trial/w test.txt' test2.txt
This is a trial line.
This is a different line.
$
$ cat test.txt
This is a trial line.

特别说明:
-n选项禁止sed编辑器输出,但p替换标记会输出修改过的行,二者结合使用效果就是只输出被替换命令修改过的行。
w替换标记会产生同样的输出,但会将输出保存到指定文件中。

替换字符
有时我们会在文本字符串中遇到一些不太方便在替换模式中使用的字符,比如正斜线(/)。替换文件中的路径名就会变得比较麻烦。比如:

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

遇到正斜线的时候,看到上面这个替换命令,瞬间觉得头晕眼花。
不过不用担心啦,sed编辑器允许选择其它字符来作为命令中的字符串分隔符:

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

提示:
上面的字符串分隔符,你可以使用任意字符,但是要保证一致,不可以sed ‘s@bin/bash#/bin/csh!’ /etc/passwd,这样的是不正确的哦。

$ sed 's@bin/bash#/bin/csh!' /etc/passwd
sed: 1: "s@bin/bash#/bin/csh!": unterminated substitute pattern

使用地址

默认情况下,在sed编辑器中使用的命令会作用于文本数据的所有行。如果只想将命令作用于特定行或某些行,我们就要使用行寻址(line addressing)
在sed编辑器中有两种形式的行寻址:

  • 以数字形式表示行区间;
  • 用文本模式来过滤出行;

以上两种形式都使用相同的格式来指定地址:
[address] command
也可以将特定地址的多个命令分组:
address {
command1
command2
command3
}
sed编辑器会将指定的每条命令作用到匹配指定地址的行上。

数字方式的行寻址

使用数字方式的行寻址时,可以用行在文本流中的行位置来引用。sed编辑器将文本流中的第一行编号为1,然后继续按序为后面的行分配行号。
在命令中指定的地址可以是单个行号,或者用起始行号、逗号以及结尾行号指定一定区间范围内的行,如果并不知到文本中到底有多少行数据,可以使用美元符号💲指定从某行开始到文本结尾的所有行。

$ sed '2s/dog/cat/' sedData1.txt
The quick brown fox jumps over the lazy dog.
The quick brown fox jumps over the lazy cat.
The quick brown fox jumps over the lazy dog.
The quick brown fox jumps over the lazy dog.
$
$ sed '2,4s/dog/cat/' sedData1.txt
The quick brown fox jumps over the lazy dog.
The quick brown fox jumps over the lazy cat.
The quick brown fox jumps over the lazy cat.
The quick brown fox jumps over the lazy cat.
$
$ sed '3,$s/dog/cat/' sedData1.txt
The quick brown fox jumps over the lazy dog.
The quick brown fox jumps over the lazy dog.
The quick brown fox jumps over the lazy cat.
The quick brown fox jumps over the lazy cat.

使用文本模式过滤器

sed编辑器允许指定文本模式来过滤出命令要作用的行,格式如下:
/pattern/command
要注意的是,必须用正斜线把pattern包起来,这样sed就会将该命令作用到包含指定文本模式的行上。

$ grep nobody /etc/passwd
nobody:*:-2:-2:Unprivileged User:/var/empty:/usr/bin/false
$
$ sed '/nobody/s/bash/csh/' /etc/passwd
nobody:*:-2:-2:Unprivileged User:/var/empty:/usr/bin/false
root:*:0:0:System Administrator:/var/root:/bin/sh
daemon:*:1:1:System Services:/var/root:/usr/bin/false
[....]

上面的命令只作用到匹配文本模式的行上。虽然使用固定文本模式能帮我们过滤出特定的值,但是它的作用还是有限,所以sed编辑器在文本模式中提供了正则表达式的特性来帮助创建匹配效果更好的模式(这里不展开正则表达式的相关知识)。

命令组合

如果需要在单行上执行多条命令,可以使用花括号将多条命令组合到一起。

$ sed '2{
quote> s/brown/green/
quote> s/fox/elephant/
quote> s/dog/cat/
quote> }' sedData1.txt
The quick brown fox jumps over the lazy dog.
The quick green elephant jumps over the lazy cat.
The quick brown fox jumps over the lazy dog.
$
$ sed '2,${
s/brown/green/
s/fox/elephant/
s/dog/cat/
}' sedData1.txt
The quick brown fox jumps over the lazy dog.
The quick green elephant jumps over the lazy cat.
The quick green elephant jumps over the lazy cat.
The quick green elephant jumps over the lazy cat.

组合中的三条命令都会作用到该地址上,当然,我们还可以指定行区间。

删除和修改行

当然,除了文本替换外,sed还提供了删除和修改行的命令。
删除命令d,会删除匹配指定寻址模式的所有行。
使用删除命令要特别小心,如果你忘记加入寻址模式的话,流中的所有文本行 都会被删除(当然原文件内容不会发生任何改变,只是文本流中的内容会被删除)

$  cat sedData1.txt
The quick brown fox jumps over the lazy dog.
The quick brown fox jumps over the lazy dog.
The quick brown fox jumps over the lazy dog.
The quick brown fox jumps over the lazy dog.
$
$ sed 'd' sedData1.txt
$
$ cat sedData2.txt
This is line no.1
This is line no.2
This is line no.3
This is line no.4
This is line no.5
$ sed '3d' sedData2.txt
This is line no.1
This is line no.2
This is line no.4
This is line no.5
$ sed '1, 3d' sedData2.txt
This is line no.4
This is line no.5
$ sed '3, $d' sedData2.txt
This is line no.1
This is line no.2
$ sed sed '/1/,/3/d' sedData2.txt
This is line no.4
This is line no.5
$ 

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

$ sed '3c\
This is a changed line of the text.' sedData2.txt
This is line no.1
This is line no.2
This is a changed line of the text.
This is line no.4
This is line no.5
$
$ sed '2,3c\
This is a changed line of the text.' sedData2.txt
This is line no.1
This is a changed line of the text.
This is line no.4
This is line no.5

示例说明:在第一个例子中,sed编辑器会修改第三行中的文本,也可以用文本模式来寻找,比如:
sed ‘/no.3/c
This is a changed line of the text.’ sedData2.txt
文本模式修改命令会修改它匹配的数据流中的任意文本行。
第二个例子,使用了地址区间,但结果是sed编辑器用一行文本替换了数据流中的两行文本,而不是逐一修改这两行文本。

插入和追加文本

sed编辑器允许向数据流插入和追加文本行,两个操作的区别是:

  • 插入(insert)命令(i)会在指定行前增加一个新行;
  • 追加(append)命令(a)会在指定行后增加一个新行;

命令格式:
sed ‘[address] command
new line’
new line中的文本会出现在sed编辑器输出中你指定的位置。

$  echo "line 2" | sed 'i\
> line 1'
line 1
line 2
$
$  echo "line 2" | sed 'a\
line 1'
line 2
line 1

通过上面的例子,我们可以在文本前面或者后面添加文本,那么想要在文本中间插入文本要怎么做呢?
这种情况下,我们必须使用寻址来告诉sed编辑器,我们要让文本出现在什么位置。所以,在使用这些命令的时候只指定一个行地址,可以匹配一个数字行号或文本模式,但是不能使用地址区间,这很说的通,因为不管你是插入还是追加,你只能是以单个行为纬度来实现这个操作,而不是在行区间的前面或后面。

$ sed '3i\
quote> This is an inserted line.' sedData2.txt
This is line no.1
This is line no.2
This is an inserted line.
This is line no.3
This is line no.4
$
$ sed '3a\
This is an appended line.' sedData2.txt
This is line no.1
This is line no.2
This is line no.3
This is an appended line.
This is line no.4
$
$ sed '3i\
quote> This is line 1 of inserting.\
quote> This is line 2 of inserting.' sedData2.txt
This is line no.1
This is line no.2
This is line 1 of inserting.
This is line 2 of inserting.
This is line no.3
This is line no.4

特别说明:
如果要插入或追加多行文本,就必须对要插入或追加的每一行新文本后面使用反斜线,知道最后一行。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章