4.6 sed入门

sed是stream editor(流编辑器)的缩写。它是文本处理中非常重要的工具。它能够完美地配合正则表达式使用,功能不同凡响。sed命令众所周知的一个用法是进行文本替换。这则攻略包括了sed命令大部分的常用技术。

4.6.1 实战演练

sed可以替换给定文本中的字符串。它可以利用正则表达式进行匹配。

  1. $ sed 's/pattern/replace_string/' file

或者

  1. $ cat file | sed 's/pattern/replace_string/'

这个命令从stdin中读取输入。

使用-i选项,可以将替换结果应用于原文件。很多用户在进行替换之后,借助重定向来保存文件:

  1. $ sed 's/text/replace/' file > newfile
  2. $ mv newfile file

其实只需要一行命令就可以搞定,例如:

  1. $ sed -i 's/text/replace/' file

之前看到的sed命令会将每一行中第一处符合样式的内容替换掉。但是如果要替换所有内容,我们需要在命令尾部加上参数g,其方法如下:

  1. $ sed 's/pattern/replace_string/g' file

后缀 /g意味着sed会替换每一处匹配。但是有时候我们不需要替换前N处匹配,而是需要替换剩下的匹配。有一个选项可以用来忽略前N处匹配,并从第N+1处开始替换。

请看下面的命令:

  1. $ echo this thisthisthis | sed 's/this/THIS/2g'
  2. thisTHISTHISTHIS
  3. $ echo this thisthisthis | sed 's/this/THIS/3g'
  4. thisthisTHISTHIS
  5.  
  6. $ echo this thisthisthis | sed 's/this/THIS/4g'
  7. thisthisthisTHIS

当需要从第N处匹配开始替换时,可以使用 /Ng

字符 /sed中作为定界符使用。我们可以像下面一样使用任意的定界符:

  1. sed 's:text:replace:g'
  2. sed 's|text|replace|g'

当定界符出现在样式内部时,我们必须用前缀 \ 对它进行转义:

  1. sed 's|te\|xt|replace|g'

| 是一个出现在样式内部并经过转义的定界符。

4.6.2 补充内容

sed命令包含多个可用于文本处理的选项。将这些选项以合理的次序组合,可以在一行命令中解决很多复杂的问题。让我们看看这些选项。

  • 移除空白行

sed移除空白行不过是小菜一碟。空白行可以用正则表达式 ^$ 进行匹配:

  1. $ sed '/^$/d' file

/pattern/d会移除匹配样式的行。

在空白行中,行尾标记紧随着行首标记。

  • 已匹配字符串标记&

sed中,用 &标记匹配样式的字符串,就能够在替换字符串时使用已匹配的内容。

例如:

  1. $ echo this is an example | sed 's/\w\+/[&]/g'
  2. [this] [is] [an] [example]

正则表达式 \w\+ 匹配每一个单词,然后我们用[&]替换它。& 对应于之前所匹配到的单词。

  • 子串匹配标记\1

& 代表匹配给定样式的字符串。但我们也可以匹配给定样式的其中一部分。来看看具体的做法。

  1. $ echo this is digit 7 in a number | sed 's/digit \([0-9]\)/\1/'
  2. this is 7 in a number

这条命令将digit 7替换为7。样式中匹配到的子串是7(pattern)用于匹配子串。模式被包括在使用斜线转义过的()中。对于匹配到的第一个子串,其对应的标记是 \1,匹配到的第二个子串是 \2,往后依次类推。下面的示例中包含了多个匹配:

  1. $ echo seven EIGHT | sed 's/\([a-z]\+\) \([A-Z]\+\)/\2 \1/'
  2. EIGHT seven

([a-z]\+)匹配第一个单词,([A-Z]\+)匹配第二个单词。\1\2用来引用它们。这种引用被称为向后引用(back referencing)。在替换部分,它们的次序被更改为\2 \1,因此结果就呈现出逆序的形式。

  • 组合多个表达式

利用管道组合多个sed命令的方法可以用下面的方式代替:

  1. sed 'expression' | sed 'expression'

它等价于:

  1. $ sed 'expression; expression'
  • 引用

sed表达式通常用单引号来引用。不过也可以使用双引号。双引号会通过对表达式求值来对其进行扩展。当我们想在sed表达式中使用一些变量字符串时,双引号就有用武之地了。

例如:

  1. $ text=hello
  2. $ echo hello world | sed "s/$text/HELLO/"
  3. HELLO world

$text的求值结果是hello