sed:删除(输入的)最后一行会停止我的脚本

jai*_*met 5 sed

我正在测试一个包含 2 个命令的sed脚本。第一个命令从输入中删除一行,第二个命令将一行附加到输入的末尾,因此:

$ cat input.txt 
Line 1
Line 2
Line 3

$ sed '/Line 1/d;$aAppended line' input.txt
Line 2
Line 3
Appended line

$ sed '/Line 2/d;$aAppended line' input.txt
Line 1
Line 3
Appended line
Run Code Online (Sandbox Code Playgroud)

到目前为止,一切都很好。但是,如果我选择删除的行恰好是输入的最后一行,则脚本中的第二个命令永远不会运行:

$ sed '/Line 3/d;$aAppended line' input.txt
Line 1
Line 2
Run Code Online (Sandbox Code Playgroud)

我了解到sed一次读取输入行,对每一行“执行”脚本,直到没有更多的行可供读取,因此我的脚本永远不会“完成”(即Appended line永远不会附加)这一事实说得通。

尽管如此,这对我来说是一个问题(我仍然需要追加Appended line)。有谁熟悉这个问题,如果是,是否有“标准解决方法”?我认为一种替代方法(删除最后一行然后附加一行)是替换

$ sed 's/Line 3/Appended line/' file.txt
Line 1
Line 2
Appended line
Run Code Online (Sandbox Code Playgroud)

这是我唯一的选择吗?

avi*_*iro 9

d手册页中的命令sed

删除模式空间。开始下一个周期。

由于多个sed命令按照提供的顺序执行,“开始下一个周期”实际上意味着在删除该行后,它停止执行可能适用于(当前周期的)已删除行的任何后续命令。因此,如果Line 3是最后一行,并且它被删除,则将开始新的循环,并且不会执行应应用于最后一行的apend命令。

为了解决这个问题,只需调换命令的顺序即可。

sed -e '$aAppended line' -e '/Line 3/d'
Run Code Online (Sandbox Code Playgroud)

或者相当于 GNU 特定代码的标准:

sed '$a\
Appended line
/Line 3/d'
Run Code Online (Sandbox Code Playgroud)

这样,文本将被附加到删除之前的 Line 3最后一行之后(并且循环将结束)。

请注意,a不会将行附加到模式空间;引用POSIX,它为以后的输出安排文本,文本[...]应在下一次尝试获取输入行 [...] 之前写入标准输出,因此它不受 影响d,甚至不受影响通过-n选项。

  • @minorChaos 命令 a 实际上将文本附加到标准输出。如果你想追加到模式空间,你可以执行 s/$/text/。此外,d 删除模式空间,但也会停止其余脚本命令的执行,因为它通过读入下一个输入行立即开始新的循环。希望这可以帮助。 (3认同)

min*_*aos 2

根据man sed,这就是d

  d      Delete pattern space.  Start next cycle.
Run Code Online (Sandbox Code Playgroud)

您的任务可以通过以下任一方式完成

$ cat input.txt | { sed '/Line 1/d;';  echo "Appended line"; } 

$ { sed '/Line 1/d;' input.txt;  echo "Appended line"; }           # by @terdon

$ SedAppend() { sed '/Line 1/d;' "$1";  echo "Appended line"; } 
$ SedAppend input.txt
Run Code Online (Sandbox Code Playgroud)

前提是您确实希望删除包含字符串“Line 1”的所有行。