流编辑器 - 字符串



替换命令

文本替换操作(如“查找和替换”)在任何文本编辑器中都很常见。在本节中,我们将说明 SED 如何执行文本替换。以下是替换命令的语法。

[address1[,address2]]s/pattern/replacement/[flags]

这里,address1address2 分别是起始地址和结束地址,可以是行号或模式字符串。这两个地址都是可选参数。模式是我们想要用替换字符串替换的文本。此外,我们还可以使用 SED 指定可选标志。

在 books.txt 文件中,我们使用逗号 (,) 分隔每一列。让我们使用竖线 (|) 分隔每一列。为此,请将逗号 (,) 替换为竖线 (|)。

[jerry]$ sed 's/,/ | /' books.txt

执行上述代码后,您将得到以下结果

1) A Storm of Swords | George R. R. Martin, 1216 
2) The Two Towers | J. R. R. Tolkien, 352 
3) The Alchemist | Paulo Coelho, 197 
4) The Fellowship of the Ring | J. R. R. Tolkien, 432 
5) The Pilgrimage | Paulo Coelho, 288 
6) A Game of Thrones | George R. R. Martin, 864 

如果您仔细观察,只会替换第一个逗号,第二个逗号保持不变。为什么?一旦模式匹配,SED 就会用替换字符串替换它并移动到下一行。默认情况下,它只替换第一个匹配项。要替换所有匹配项,请使用 SED 的全局标志 (g),如下所示

[jerry]$ sed 's/,/ | /g' books.txt

执行上述代码后,您将得到以下结果

1) A Storm of Swords | George R. R. Martin | 1216 
2) The Two Towers | J. R. R. Tolkien | 352 
3) The Alchemist | Paulo Coelho | 197 
4) The Fellowship of the Ring | J. R. R. Tolkien | 432 
5) The Pilgrimage | Paulo Coelho | 288 
6) A Game of Thrones | George R. R. Martin | 864

现在所有逗号 (,) 都被替换为竖线 (|)。

我们可以指示 SED 仅在模式匹配成功时执行文本替换。以下示例仅当一行包含模式 The Pilgrimage 时,才将逗号 (,) 替换为竖线 (|)。

[jerry]$ sed '/The Pilgrimage/ s/,/ | /g' books.txt 

执行上述代码后,您将得到以下结果

1) A Storm of Swords, George R. R. Martin, 1216 
2) The Two Towers, J. R. R. Tolkien, 352 
3) The Alchemist, Paulo Coelho, 197 
4) The Fellowship of the Ring, J. R. R. Tolkien, 432 
5) The Pilgrimage | Paulo Coelho | 288 
6) A Game of Thrones, George R. R. Martin, 864

除此之外,SED 可以替换模式的特定匹配项。让我们只用竖线 (|) 替换逗号 (,) 的第二个实例。

[jerry]$ sed 's/,/ | /2' books.txt

执行上述代码后,您将得到以下结果

1) A Storm of Swords, George R. R. Martin | 1216 
2) The Two Towers, J. R. R. Tolkien | 352 
3) The Alchemist, Paulo Coelho | 197 
4) The Fellowship of the Ring, J. R. R. Tolkien | 432 
5) The Pilgrimage,Paulo Coelho | 288 
6) A Game of Thrones, George R. R. Martin  | 864

在上面的示例中,SED 命令末尾的数字(或标志所在的位置)表示第二个匹配项。

SED 提供了一个有趣的特性。执行替换后,SED 提供了一个选项,仅显示已更改的行。为此,SED 使用p标志,该标志表示打印。以下示例仅列出已更改的行。

[jerry]$ sed -n 's/Paulo Coelho/PAULO COELHO/p' books.txt

执行上述代码后,您将得到以下结果

3) The Alchemist, PAULO COELHO, 197 
5) The Pilgrimage, PAULO COELHO, 288 

我们也可以将已更改的行存储在另一个文件中。要实现此结果,请使用w标志。以下示例演示了如何操作。

[jerry]$ sed -n 's/Paulo Coelho/PAULO COELHO/w junk.txt' books.txt

我们使用了相同的 SED 命令。让我们验证一下junk.txt文件的内容。

[jerry]$ cat junk.txt

执行上述代码后,您将得到以下结果

3) The Alchemist, PAULO COELHO, 197 
5) The Pilgrimage, PAULO COELHO, 288

要执行不区分大小写的替换,请使用i标志,该标志表示忽略大小写。以下示例执行不区分大小写的替换。

[jerry]$ sed  -n 's/pAuLo CoElHo/PAULO COELHO/pi' books.txt

执行上述代码后,您将得到以下结果

3) The Alchemist, PAULO COELHO, 197 
5) The Pilgrimage, PAULO COELHO, 288

到目前为止,我们只使用正斜杠 (/) 字符作为分隔符,但我们也可以使用竖线 (|)、at 符号 (@)、脱字符 (^)、感叹号 (!) 作为分隔符。以下示例演示了如何使用其他字符作为分隔符。

假设您需要将路径/bin/sed替换为/home/jerry/src/sed/sed-4.2.2/sed。因此,您的 SED 命令如下所示

[jerry]$ echo "/bin/sed" | sed 's/\/bin\/sed/\/home\/jerry\/src\/sed\/sed-4.2.2\/sed/'

执行上述代码后,您将得到以下结果

/home/jerry/src/sed/sed-4.2.2/sed

我们可以使此命令更具可读性和易于理解。让我们使用竖线 (|) 作为分隔符,并查看结果。

[jerry]$ echo "/bin/sed" | sed 's|/bin/sed|/home/jerry/src/sed/sed-4.2.2/sed|'

执行上述代码后,您将得到以下结果

/home/jerry/src/sed/sed-4.2.2/sed

确实!我们得到了相同的结果,并且语法更具可读性。类似地,我们可以使用“at”符号 (@) 作为分隔符,如下所示

[jerry]$ echo "/bin/sed" | sed 's@/bin/sed@/home/jerry/src/sed/sed-4.2.2/sed@'

执行上述代码后,您将得到以下结果

/home/jerry/src/sed/sed-4.2.2/sed 

除此之外,我们还可以使用脱字符 (^) 作为分隔符。

[jerry]$ echo "/bin/sed" | sed 's^/bin/sed^/home/jerry/src/sed/sed-4.2.2/sed^'

执行上述代码后,您将得到以下结果

/home/jerry/src/sed/sed-4.2.2/sed 

我们还可以使用感叹号 (!) 作为分隔符,如下所示

[jerry]$ echo "/bin/sed" | sed 's!/bin/sed!/home/jerry/src/sed/sed-4.2.2/sed!'

执行上述代码后,您将得到以下结果

/home/jerry/src/sed/sed-4.2.2/sed 

通常,反斜杠 (/) 用作分隔符,但有时使用 SED 支持的其他分隔符会更方便。

创建子字符串

我们学习了强大的替换命令。让我们看看是否可以从匹配的文本中找到子字符串。让我们通过一个示例了解如何做到这一点。

让我们考虑以下文本

[jerry]$ echo "Three One Two"

假设我们必须将其排列成一个序列。意思是,它应该首先打印 One,然后打印 Two,最后打印 Three。以下单行代码可以满足需要。

echo "Three One Two" | sed 's|\(\w\+\) \(\w\+\) \(\w\+\)|\2 \3 \1|'

请注意,在上面的示例中,竖线 (|) 用作分隔符。

在 SED 中,可以通过使用分组运算符来指定子字符串,并且必须以转义字符为前缀,即\(\)

\w是一个正则表达式,它匹配任何字母、数字或下划线,并且“+”用于匹配多个字符。换句话说,正则表达式\(\w\+\)匹配输入字符串中的单个单词。

在输入字符串中,有三个单词用空格分隔,因此有三个用空格分隔的正则表达式。第一个正则表达式存储第一个单词,即 Three,第二个存储单词One,第三个存储单词Two

这些子字符串由\N引用,其中 N 是子字符串编号。因此,\2打印第二个子字符串,即One;\3打印第三个子字符串,即Two;\1打印第一个子字符串,即Three

让我们用逗号 (,) 分隔这些单词,并相应地修改正则表达式。

[jerry]$ echo "Three,One,Two" | sed 's|\(\w\+\),\(\w\+\),\(\w\+\)|\2,\3,\1|'

执行上述代码后,您将得到以下结果

One,Two,Three

请注意,现在正则表达式中使用逗号 (,) 代替空格。

字符串替换标志(仅限 GNU SED)

在上一节中,我们看到了替换命令的一些示例。GNU SED 提供了一些可以在替换字符串中使用的特殊转义序列。请注意,这些字符串替换标志是 GNU 特定的,可能不适用于其他版本的 SED。这里我们将讨论字符串替换标志。

  • \L:当在替换字符串中指定 \L 时,它会将 \L 后单词的其余所有字符视为小写字符。例如,字符“ULO”被视为小写字符。

[jerry]$ sed -n 's/Paulo/PA\LULO/p' books.txt

执行上述代码后,您将得到以下结果

3) The Alchemist, PAulo Coelho, 197
5) The Pilgrimage, PAulo Coelho, 288
  • \u:当在替换字符串中指定 \u 时,它会将 \u 后面的直接字符视为大写字符。在以下示例中,\u 用于字符“a”和“o”之前。因此,SED 将这些字符视为大写字母。

[jerry]$ sed -n 's/Paulo/p\uaul\uo/p' books.txt

执行上述代码后,您将得到以下结果

3) The Alchemist, pAulO Coelho, 197 
5) The Pilgrimage, pAulO Coelho, 288
  • \U:当在替换字符串中指定 \U 时,它会将 \U 后单词的其余所有字符视为大写字符。

[jerry]$ sed -n 's/Paulo/\Upaulo/p' books.txt 

执行上述代码后,您将得到以下结果

3) The Alchemist, PAULO Coelho, 197 
5) The Pilgrimage, PAULO Coelho, 288
  • \E:此标志应与 \L 或 \U 一起使用。它停止由标志 \L 或 \U 启动的转换。在以下示例中,只有第一个单词被替换为大写字母。

[jerry]$ sed -n 's/Paulo Coelho/\Upaulo \Ecoelho/p' books.txt

执行上述代码后,您将得到以下结果

3) The Alchemist, PAULO coelho, 197 
5) The Pilgrimage, PAULO coelho, 288
广告