最后一次与sed匹配后追加行

时间:2016-06-19 16:26:46

标签: bash sed

我们假设我有以下输入。

Header
thing0 some info
thing4 some info
thing4 some info
thing4 some info
thing2 some info
thing2 some info
thing3 some info

现在,我希望能够追加" foo"在#34; thing4"的最后一次成功比赛中像这样。

Header
thing0 some info
thing4 some info
thing4 some info
thing4 some info
foo
thing2 some info
thing2 some info
thing3 some info

订单不一定得到保证,但此示例中的顺序编号只是为了表明在某些文本行之前有一个可搜索的关键字,并且它们在输入时通常组合在一起,但不能保证。

6 个答案:

答案 0 :(得分:4)

使用单个awk,你可以这样做:

awk 'FNR==NR{ if (/thing4/) p=NR; next} 1; FNR==p{ print "foo" }' file file

Header
thing0 some info
thing4 some info
thing4 some info
thing4 some info
foo
thing2 some info
thing2 some info
thing3 some info

早期解决方案:您可以使用tac + awk + tac

tac file | awk '!p && /thing4/{print "foo"; p=1} 1' | tac

答案 1 :(得分:3)

这可能适合你(GNU sed):

sed '1h;1!H;$!d;x;s/.*thing4[^\n]*/&\nfoo/' file

将文件拖入内存并使用正则表达式的贪婪在最后一次出现所需模式后放置所需的字符串。

更高效(使用最少内存)但更难理解的是:

sed '/thing4[^\n]*/,$!b;//{x;//p;g};//!H;$!d;x;s//&\nfoo/' file

解释留待读者解读。

答案 2 :(得分:1)

啊,我找到了 堆栈上here。补充了@anubhava的解决方案,该解决方案利用tac翻转附加然后翻转再次创建附加在最后一次出现的错觉。谢谢你的帮助。

tac | sed '0,/thing4/s/thing4/foo\n&/' | tac

答案 3 :(得分:1)

可能就像

一样简单
awk 'BEGIN{RS="^$"}
        {$0=gensub(/(.*thing4[^\n]*\n)/,"\\1foo\n","1",$0);printf "%s",$0}' file

示例输入

Header
thing0 some info
thing4 some info
thing4 some info
thing4 some info
thing2 some info
thing2 some info
thing3 some info

示例输出

Header
thing0 some info
thing4 some info
thing4 some info
thing4 some info
foo
thing2 some info
thing2 some info
thing3 some info

这里会发生什么

  1. 我们将记录分隔符RS设置为空,即^$,我们将整个文件视为一条记录。

  2. gensub中的
  3. .*thing4[^\n]*\n会匹配包含thing4的最后一行的所有内容。

  4. gensub允许通过特殊调整\1重用第一个匹配的模式。由于替换是字符串,我们需要添加额外的\,因此整个替换变为\\1foo\n\n确实是一个转义序列,因此我们不需要在n之前将两个向后缩减。

  5. 备注

    1. 解决方案特定于gnu-awk,但也可以针对其他版本进行轻松调整。
    2. 由于整个文件应该被读入内存,这个解决方案最适合小文件,仍然只有几兆字节的文件。

答案 4 :(得分:1)

这些行总是按关键字分组还不完全清楚。如果是这样,那么这种单awk方法也应该起作用:

awk -v s=thing3 -v t=foo 'END{if(f) print t} {if($0~s)f=1; else if(f) {print t; f=0}}1' file

或:

awk -v s=thing0 -v t=foo 'END{if(f)print t} {f=$0~s} f,!f{if(!f)print t}1' file

答案 5 :(得分:0)

sed -e "$(grep -n 'thing4' file |tail -1|cut -f1 -d':')a foo" file

使用shell和grep获取包含模式的最后一行编号,然后使用该编号作为sed append命令的地址。