sed 命令中的 :a;$!N; 是什么意思?

sed 命令中的 :a;$!N; 是什么意思?
$ (echo hello; echo there) | sed ':a;$!N;s/\n/string/;ta'
hellostringthere

上面的sed命令用字符串“string”替换换行符。但我不知道:a;$!N;s/\n/string/;ta单引号内的含义。我知道中间部分s/\n/string/。但我不知道第一部分(:a;$!N;)和最后ta一部分()的作用。

答案1

这些是公认的神秘sed命令。具体来说(来自man sed):

:标签
         b 和 t 命令的标签。

t 标签
         如果自读取最后一行输入并且自最后一条 t 或 T 命令以来 as/// 已成功完成替换,则分支到标签;如果省略标签,则分支到脚本末尾。

n N 将下一行输入读取/附加到模式空间。

因此,您发布的脚本可以分解为(为方便阅读添加了空格):

sed ':a;  $!N;  s/\n/string/;  ta'
     ---  ----  -------------  --
      |     |        |          |--> go back (`t`) to `a`
      |     |        |-------------> substitute newlines with `string`
      |     |----------------------> If this is not the last line (`$!`), append the 
      |                              next line to the pattern space.
      |----------------------------> Create the label `a`.

基本上,这个操作可以用伪代码写成

while (not end of line){
    append current line to this one and replace \n with 'string'
}

您可以通过更复杂的输入示例更好地理解这一点:

$ printf "line1\nline2\nline3\nline4\nline5\n" | sed ':a;$!N;s/\n/string/;ta'
line1stringline2stringline3stringline4stringline5

我不太清楚为什么!$需要这个。据我所知,你可以用以下方法获得相同的输出

printf "line1\nline2\nline3\nline4\nline5\n" | sed ':a;N;s/\n/string/;ta'

答案2

我发布这个答案是因为我发现很多人对为什么N执行时(通过行寻址字符串)排除最后一行$!,因为OP对:a;$!N; Ased 命令,不仅在他发布的具体内容。

$!N好吧,使用而不是的好处N在所提出的示例中并不明显(由 OP 和 @terdon 提出),因为在命令之后的最后一行没有执行任何“重要”(继续阅读)命令N。(实际上,如果删除该行地址,结果是相同的。)

在更复杂的示例中(例如,替换this sentence文件中的两个单词,有时出现在一行中,有时出现在两行中),排除N命令的最后一行可能至关重要!如果不排除最后一行,则在执行N该行时,sed将立即命中EOF并退出,从而阻止执行所有后续命令(以及分支命令,即tb)。

在所示的过于简单的示例中,我们可以安全地删除$!并让其sed执行失败N并返回,因为s如果执行中止的命令,它不会执行任何操作,因为没有\n匹配项。

相关内容