$ (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
并退出,从而阻止执行所有后续命令(以及分支命令,即t
和b
)。
在所示的过于简单的示例中,我们可以安全地删除$!
并让其sed
执行失败N
并返回,因为s
如果执行中止的命令,它不会执行任何操作,因为没有\n
匹配项。