删除与模式匹配的前 N ​​行,保留最后一行

删除与模式匹配的前 N ​​行,保留最后一行

我需要删除与正则表达式匹配的前 N ​​行,但保留最后一行。

28test
32test
something else
6test
something else
something else
4test
entirelysomethingelse

我想要这样的东西。

something else
something else
something else
4test
entirelysomethingelse

尝试使用sed,似乎它只适用于一行和多个字符串。

我使用了正则表达式:^(.*test)$

答案1

仅保留最后一个匹配行的一个简单方法是反向打印输入,仅选择第一个匹配行,然后在管道中反向打印输出。假设tacGNU 核心实用程序可供您使用:

tac input_file | awk '!/test$/ || !seen++' | tac >output_file

就地编辑(按照您在评论)通常是通过将命令包装在脚本或函数中来获得的,该脚本或函数负责用处理后的输出覆盖作为参数给出的文件。

tmpdir=$(mktemp -d)
cp input_file "$tmpdir/file"
tac "$tmpdir/file" | awk '!/test$/ || !seen++' | tac >input_file
rm -r "$tmpdir"

如果您的 shell 支持该pipefail选项(我可以使用setopt PIPE_FAIL、 busybox ash、yash 成功测试 bash、ksh93、mksh、zsh),则可以使用set -eand使这更安全set -o pipefail:错误(包括管道中任何地方发生的错误)将使执行停止之前临时文件被删除。

在支持它的平台上,假设您不关心在出现问题时丢失数据,您还可以使用:

{ rm file; tac | awk '!/test$/ || !seen++' | tac >file; } <file

请注意,这将更改 的索引节点file(就像许多常用工具提供的就地编辑选项一样)。

相反,如果您想删除第一个n匹配线,假设这里n= 2:

awk '!/test$/ || ++seen > 2' input_file >output_file

awk在这种情况下, GNU 能够导入其他库(特别是自带的“就地”库) ,可以方便地进行就地编辑gawk

awk -i inplace '...' file

有关此内容的更多信息,请参阅这个另一个答案在 U&L 上。

答案2

至于选项 - “删除模式匹配的前 N ​​行”
在 上sed,您可以在保留空间(附加缓冲区)中组织一个计数器。

sed -r '/test$/!b;x;s/$/-/;/-{4}/!{x;d};x' file

/test$/!b- 如果没有模式匹配则无条件跳转到末尾。
x- 交换模式和保留空间的内容。
s/$/-/- 对于每个匹配,在计数器末尾添加一个字符,在我的例子中是一个连字符。
/-{4}/!{x;d}- 如果计数器包含的字符少于 4 个字符,则删除模式空间中的行。

相关内容