我们假设我有以下输入。
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
订单不一定得到保证,但此示例中的顺序编号只是为了表明在某些文本行之前有一个可搜索的关键字,并且它们在输入时通常组合在一起,但不能保证。
答案 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)
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
这里会发生什么
我们将记录分隔符RS设置为空,即^$
,我们将整个文件视为一条记录。
.*thing4[^\n]*\n
会匹配包含thing4
的最后一行的所有内容。
gensub允许通过特殊调整\1
重用第一个匹配的模式。由于替换是字符串,我们需要添加额外的\
,因此整个替换变为\\1foo\n
。 \n
确实是一个转义序列,因此我们不需要在n
之前将两个向后缩减。
备注强>
答案 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命令的地址。