4.6 sed入门
sed
是stream editor(流编辑器)的缩写。它是文本处理中非常重要的工具。它能够完美地配合正则表达式使用,功能不同凡响。sed
命令众所周知的一个用法是进行文本替换。这则攻略包括了sed
命令大部分的常用技术。
4.6.1 实战演练
sed
可以替换给定文本中的字符串。它可以利用正则表达式进行匹配。
- $ sed 's/pattern/replace_string/' file
或者
- $ cat file | sed 's/pattern/replace_string/'
这个命令从stdin
中读取输入。
使用-i
选项,可以将替换结果应用于原文件。很多用户在进行替换之后,借助重定向来保存文件:
- $ sed 's/text/replace/' file > newfile
- $ mv newfile file
其实只需要一行命令就可以搞定,例如:
- $ sed -i 's/text/replace/' file
之前看到的sed
命令会将每一行中第一处符合样式的内容替换掉。但是如果要替换所有内容,我们需要在命令尾部加上参数g
,其方法如下:
- $ sed 's/pattern/replace_string/g' file
后缀 /g
意味着sed
会替换每一处匹配。但是有时候我们不需要替换前N处匹配,而是需要替换剩下的匹配。有一个选项可以用来忽略前N处匹配,并从第N+1处开始替换。
请看下面的命令:
- $ echo this thisthisthis | sed 's/this/THIS/2g'
- thisTHISTHISTHIS
- $ echo this thisthisthis | sed 's/this/THIS/3g'
- thisthisTHISTHIS
- $ echo this thisthisthis | sed 's/this/THIS/4g'
- thisthisthisTHIS
当需要从第N处匹配开始替换时,可以使用 /Ng
。
字符 /
在sed
中作为定界符使用。我们可以像下面一样使用任意的定界符:
- sed 's:text:replace:g'
- sed 's|text|replace|g'
当定界符出现在样式内部时,我们必须用前缀 \
对它进行转义:
- sed 's|te\|xt|replace|g'
|
是一个出现在样式内部并经过转义的定界符。
4.6.2 补充内容
sed
命令包含多个可用于文本处理的选项。将这些选项以合理的次序组合,可以在一行命令中解决很多复杂的问题。让我们看看这些选项。
- 移除空白行
用sed
移除空白行不过是小菜一碟。空白行可以用正则表达式 ^$
进行匹配:
- $ sed '/^$/d' file
/pattern/d
会移除匹配样式的行。
在空白行中,行尾标记紧随着行首标记。
- 已匹配字符串标记
&
在sed
中,用 &
标记匹配样式的字符串,就能够在替换字符串时使用已匹配的内容。
例如:
- $ echo this is an example | sed 's/\w\+/[&]/g'
- [this] [is] [an] [example]
正则表达式 \w\+
匹配每一个单词,然后我们用[&]
替换它。&
对应于之前所匹配到的单词。
- 子串匹配标记
\1
&
代表匹配给定样式的字符串。但我们也可以匹配给定样式的其中一部分。来看看具体的做法。
- $ echo this is digit 7 in a number | sed 's/digit \([0-9]\)/\1/'
- this is 7 in a number
这条命令将digit 7
替换为7
。样式中匹配到的子串是7
。(pattern)
用于匹配子串。模式被包括在使用斜线转义过的()
中。对于匹配到的第一个子串,其对应的标记是 \1
,匹配到的第二个子串是 \2
,往后依次类推。下面的示例中包含了多个匹配:
- $ echo seven EIGHT | sed 's/\([a-z]\+\) \([A-Z]\+\)/\2 \1/'
- EIGHT seven
([a-z]\+)
匹配第一个单词,([A-Z]\+)
匹配第二个单词。\1
和\2
用来引用它们。这种引用被称为向后引用(back referencing)。在替换部分,它们的次序被更改为\2 \1
,因此结果就呈现出逆序的形式。
- 组合多个表达式
利用管道组合多个sed
命令的方法可以用下面的方式代替:
sed 'expression' | sed 'expression'
它等价于:
$ sed 'expression; expression'
- 引用
sed
表达式通常用单引号来引用。不过也可以使用双引号。双引号会通过对表达式求值来对其进行扩展。当我们想在sed
表达式中使用一些变量字符串时,双引号就有用武之地了。
例如:
- $ text=hello
- $ echo hello world | sed "s/$text/HELLO/"
- HELLO world
$text
的求值结果是hello
。