bash 在与 sed 的最后一场比赛之后追加一行
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/37909388/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Append line after last match with sed
提问by Mozzy
Let's assume I have the following input.
假设我有以下输入。
Header
thing0 some info
thing4 some info
thing4 some info
thing4 some info
thing2 some info
thing2 some info
thing3 some info
Now, I want to be able to append "foo" on the last successful match of "thing4" like this.
现在,我希望能够像这样在“thing4”的最后一次成功匹配上附加“foo”。
Header
thing0 some info
thing4 some info
thing4 some info
thing4 some info
foo
thing2 some info
thing2 some info
thing3 some info
The order is not necessarily guaranteed, but the sequential numbering in this example is just to show that there is a searchable keyword before certain lines of text and that they are are usuallygrouped together on input, but it is not guaranteed.
顺序不一定保证,但本例中的顺序编号只是为了表明在某些文本行之前有一个可搜索的关键字,并且它们通常在输入时组合在一起,但不保证。
采纳答案by anubhava
Using single awk you can do:
使用单个 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
Earlier Solution:You can use tac + awk + tac
:
较早的解决方案:您可以使用tac + awk + tac
:
tac file | awk '!p && /thing4/{print "foo"; p=1} 1' | tac
回答by potong
This might work for you (GNU sed):
这可能对你有用(GNU sed):
sed '1h;1!H;$!d;x;s/.*thing4[^\n]*/&\nfoo/' file
Slurp the file into memory and use the greed of the regexp to place the required string after the last occurrence of the required pattern.
将文件放入内存并使用正则表达式的贪婪将所需的字符串放在最后一次出现所需的模式之后。
A more efficient (uses minimum memory) but harder to understand is:
更有效(使用最少内存)但更难理解的是:
sed '/thing4[^\n]*/,$!b;//{x;//p;g};//!H;$!d;x;s//&\nfoo/' file
The explanation is left to the reader to puzzle over.
解释留给读者去琢磨。
回答by Mozzy
Ah, I found it
hereon the stack. Supplemented with @anubhava 's solution which made use of tac
to flip append then flip again creating the illusion of appending on the last occurrence. Thanks for the help.
嗯,我发现
这里的堆栈。补充了@anubhava 的解决方案,该解决方案利用tac
翻转追加然后再次翻转创造了最后一次追加的错觉。谢谢您的帮助。
tac | sed '0,/thing4/s/thing4/foo\n&/' | tac
tac | sed '0,/thing4/s/thing4/foo\n&/' | tac
回答by sjsam
It could be as simple as
它可以很简单
awk 'BEGIN{RS="^$"}
{Header
thing0 some info
thing4 some info
thing4 some info
thing4 some info
thing2 some info
thing2 some info
thing3 some info
=gensub(/(.*thing4[^\n]*\n)/,"\1foo\n","1",Header
thing0 some info
thing4 some info
thing4 some info
thing4 some info
foo
thing2 some info
thing2 some info
thing3 some info
);printf "%s",awk -v s=thing3 -v t=foo 'END{if(f) print t} {if(awk -v s=thing0 -v t=foo 'END{if(f)print t} {f=sed -e "$(grep -n 'thing4' file |tail -1|cut -f1 -d':')a foo" file
~s} f,!f{if(!f)print t}1' file
~s)f=1; else if(f) {print t; f=0}}1' file
}' file
Sample input
样本输入
##代码##Sample Output
样本输出
##代码##What happens here
这里发生了什么
We set the Record Separator RS to null ie
^$
, we treat the entire file as one record..*thing4[^\n]*\n
in gensub matches anything till the last line which containthing4
.gensub allows to reuse the first matched pattern by a special adjustment
\1
. Since the replacement is a string, we need to add an extra\
so the whole replacement became\\1foo\n
. The\n
is indeed an escape sequence, so we dont' need to put two backward slashed beforen
.
我们将记录分隔符 RS 设置为空,即
^$
,我们将整个文件视为一个记录。.*thing4[^\n]*\n
在 gensub 中匹配任何内容,直到包含thing4
.gensub 允许通过特殊调整重用第一个匹配的模式
\1
。由于替换是一个字符串,我们需要添加一个额外的,\
所以整个替换变成了\\1foo\n
. 的\n
的确是一个转义序列,所以我们不”需要把前两落后削减n
。
Notes
笔记
- Solution is gnu-awk specific, but could be easilty tweaked for other versions as well.
- Since the whole file should be read to the memory, this solution best suits small files, still nbd with files spanning a few megabytes.
- 解决方案是特定于 gnu-awk 的,但也可以针对其他版本进行轻松调整。
- 由于应该将整个文件读取到内存中,因此该解决方案最适合小文件,仍然是 nbd 文件跨越几兆字节。
回答by Scrutinizer
It is not entirely clear if the lines are always grouped by keyword. If so, then this single awk
approach should work too:
这些行是否总是按关键字分组尚不完全清楚。如果是这样,那么这种单一awk
方法也应该有效:
or:
或者:
##代码##回答by yourlord
Use the shell and grep to obtain the last line number that contains the pattern, then use that number as the address for the sed append command.
使用 shell 和 grep 获取包含该模式的最后一行编号,然后使用该编号作为 sed append 命令的地址。