Shell 使用sed替换文本

Shell 使用sed替换文本sed是stream editor(流编辑器)的缩写。它最常见的用法是进行文本替换。这则攻略中包括了大量sed命令的常见用法。

Shell使用sed替换文本

实战演练

sed可以使用另一个字符串来替换匹配模式。模式可以是简单的字符串或正则表达式:

$ sed 's/pattern/replace_string/' file

sed也可以从stdin中读取输入:

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

如果你用的是vi编辑器,你会发现它用于替换文本的命令和sed的非常相似。sed默认只打印出被替换的文本,可以将其用于管道中。

$ cat /etc/passwd | cut -d : -f1,3 | sed 's/:/ - UID: /'
root - UID: 0
bin - UID: 1
...

(1) 选项-i会使得sed用修改后的数据替换原始文件:

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

(2) 之前的例子只替换了每行中模式首次匹配的内容。g标记可以使sed执行全局替换:

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

/#g标记可以使sed替换第N次出现的匹配:

$ echo thisthisthisthis | sed 's/this/THIS/2g'
thisTHISTHISTHIS

$ echo thisthisthisthis | sed 's/this/THIS/3g'
thisthisTHISTHIS

$ echo thisthisthisthis | sed 's/this/THIS/4g'
thisthisthisTHIS

sed命令会将s之后的字符视为命令分隔符。这允许我们更改默认的分隔符/

sed 's:text:replace:g'
sed 's|text|replace|g'

如果作为分隔符的字符出现在模式中,必须使用\对其进行转义:

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

\|是出现在模式中被转义的分隔符。

补充内容

sed命令可以使用正则表达式作为模式,另外还包含了大量可用于文本处理的选项。

  1. 移除空行

有了正则表达式的支持,移除空行不过是小菜一碟。空行可以用正则表达式 ^$ 进行匹配。最后的/d告诉sed不执行替换操作,而是直接删除匹配到的空行:

$ sed '/^$/d' file
  1. 直接在文件中替换

如果将文件名传递给sed,它会将文件内容输出到stdout。要是我们想就地(in place)修改文件内容,可以使用选项-i

$ sed 's/PATTERN/replacement/' -i filename

例如,使用指定的数字替换文件中所有3位数的数字:

$ cat sed_data.txt
11 abc 111 this 9 file contains 111 11 88 numbers 0000

$ sed -i 's/\b[0-9]\{3\}\b/NUMBER/g' sed_data.txt
$ cat sed_data.txt
11 abc NUMBER this 9 file contains NUMBER 11 88 numbers 0000

上面的单行命令只替换了所有的3位数字。正则表达式\b[0-9]\{3\}\b用于匹配3位数字。[0-9]表示数字取值范围是从0到9。{3}表示匹配之前的数字3次。\{3\}中的\用于转义{}\b表示单词边界。

有一种值得推荐的做法是先使用不带i选项的sed命令,以确保正则表达式没有问题,如果结果符合要求,再加入-i选项将更改写入文件。另外,你也可以使用下列形式的sed

sed -i.bak 's/abc/def/' file

这时的sed不仅替换文件内容,还会创建一个名为file.bak的文件,其中包含着原始文件内容的副本。

  1. 已匹配字符串标记(&

sed中,我们可以用&指代模式所匹配到的字符串,这样就能够在替换字符串时使用已匹配的内容:

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

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

  1. 子串匹配标记(\1

&指代匹配给定模式的字符串。我们还可以使用\#来指代出现在括号中的部分正则表达式(注:子模式)所匹配到的内容:

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

这条命令将digit 7替换为7\(pattern\)用于匹配子串,在本例中匹配到的子串是7。子模式被放入使用反斜线转义过的()中。对于匹配到的第一个子串,其对应的标记是\1,匹配到的第二个子串是\2,往后以此类推。

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

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

  1. 组合多个表达式

可以利用管道组合多个sed命令,多个模式之间可以用分号分隔,或是使用选项-e PATTERN

sed 'expression' | sed 'expression'

它等同于

$ sed 'expression; expression'

或者

$ sed -e 'expression' -e 'expression'

考虑下列示例:

$ echo abc | sed 's/a/A/' | sed 's/c/C/'
AbC
$ echo abc | sed 's/a/A/;s/c/C/'
AbC
$ echo abc | sed -e 's/a/A/' -e 's/c/C/'
AbC
  1. 引用

sed表达式通常用单引号来引用。不过也可以使用双引号。shell会在调用sed前先扩展双引号中的内容。如果想在sed表达式中使用变量,双引号就能派上用场了。
例如:

$ text=hello
$ echo hello world | sed "s/$text/HELLO/"
HELLO world

$text的求值结果是hello

Python教程

Java教程

Web教程

数据库教程

图形图像教程

大数据教程

开发工具教程

计算机教程

Shell 实例