📜  流编辑器-字符串

📅  最后修改于: 2020-10-16 06:18:06             🧑  作者: Mango


替代命令

诸如“查找和替换”之类的文本替换操作在任何文本编辑器中都是常见的。在本节中,我们说明了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可以替换特定样式的图案。让我们仅用竖线(|)替换comma(,)的第二个实例。

[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

到目前为止,我们只使用了foreslash(/)字符作为分隔符,但是我们也可以使用竖线(|),sign(@),caret(^),感叹号(!)作为分隔符。下面的示例演示如何使用其他字符作为分隔符。

让我们假设您需要将路径/ 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 

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

[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"

假设我们必须将其排列成一个序列。意思是,它应该先打印一个,然后打印两个,最后打印三个。以下一线需要帮助。

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打印第一个子字符串,即3

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

[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之后的立即字符视为大写字符。在以下示例中,在字符“ a”和“ o”之前使用\ u。因此,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