sed替换最后一行匹配模式

TTT*_*TTT 14 regex bash sed

给定这样的文件:

a
b
a
b
Run Code Online (Sandbox Code Playgroud)

我希望能够用来sed替换文件中包含"a"实例的最后一行.因此,如果我想用"c"替换它,那么输出应该如下所示:

a
b
c
b
Run Code Online (Sandbox Code Playgroud)

请注意,无论可能遇到多少匹配,或者确切了解所需模式或文件内容的详细信息,我都需要这样做.提前致谢.

gle*_*man 12

不完全是sed:

tac file | sed '/a/ {s//c/; :loop; n; b loop}' | tac
Run Code Online (Sandbox Code Playgroud)

测试

% printf "%s\n" a b a b a b | tac | sed '/a/ {s//c/; :loop; n; b loop}' | tac
a
b
a
b
c
b
Run Code Online (Sandbox Code Playgroud)

反转文件,然后进行第一次匹配,进行替换,然后无条件地填充文件的其余部分.然后重新反转文件.

注意,空正则表达式(此处为s//c/)表示重用前一个正则表达式(/a/)

除了非常简单的程序,我不是一个巨大的sed粉丝.我会用awk:

tac file | awk '/a/ && !seen {sub(/a/, "c"); seen=1} 1' | tac
Run Code Online (Sandbox Code Playgroud)

  • +1 @glenn jackman,但我不明白在sed命令中使用`:loop,n,b loop`,你能解释一下吗? (2认同)
  • `tac file | sed'1,/ a/s/a/c /'| tac` (2认同)
  • 结果是sed没有在同一行上开始和结束的范围,所以如果文件中的最后一行是匹配,我的想法将失败.GNU sed有针对该特定问题的修复,`0,/ a/s/a/c /`将执行我想要的`1,/ a /`. (2认同)

mkl*_*nt0 5

这里有很多很好的答案;这是一个概念上简单的两遍sed解决方案tail符合 POSIX 标准并且不会将整个文件读入内存,类似于Eran Ben-Natan 的方法

sed "$(sed -n '/a/ =' file | tail -n 1)"' s/a/c/' file
Run Code Online (Sandbox Code Playgroud)
  • sed -n '/a/=' file输出数字线(函数=)匹配正则表达式a,以及tail -n 1提取输出的最后一行,即在文件中的行的数量file含有最后的正则表达式的发生。

  • 将命令替换$(sed -n '/a/=' file | tail -n 1)直接' s/a/c'放在导致外部sed脚本(例如3 s/a/c/(带有样本输入))之前,它仅在最后一个出现正则表达式的地方执行所需的替换。

如果在输入文件中找不到模式,则整个命令是有效的空操作。

  • @TTT:他_主要_符合 POSIX(`tail -1` 必须是 `tail -n 1`),但主要是他的嵌入式命令(`grep` + `cut` + `tail`)不必要地复杂。此外,他的命令使用传统的命令替换语法(`\`...\``)而不是现代的`$(...)` 语法。 (2认同)