在第二个模式的最后一次出现之后进行两次模式搜索和追加行

时间:2013-02-28 10:43:08

标签: linux unix sed awk grep

以下sed问题在过去两天给我带来了很多麻烦。

我有以下文件(iptables)

someline

someline

*filter

:INPUT ACCEPT [0:0]

:FORWARD ACCEPT [0:0]

:OUTPUT ACCEPT [0:0]

someline

我想使用sed搜索模式*filter,如果匹配则搜索第二个模式[0:0],然后在第二个模式的最后一次出现后添加一行。

然后(理想情况下)会导致:

someline

someline

*filter

:INPUT ACCEPT [0:0]

:FORWARD ACCEPT [0:0]

:OUTPUT ACCEPT [0:0]

TESTLINEADDEDBYSED

someline

这里的论坛给了我一个良好的开端,但我无法解决这个具体问题。

到目前为止,我有以下解决方案,但它在第一次出现第二个模式[0:0]后添加了一行:

sed -n '/\*filter/{:a;N;/^\n/s/^\n//;/\[0:0\]/{!ba;p;s/.*/TESTLINEADDEDBYSED/;};ba}; p' file

我假设第二个分支中的.*我会消耗(读取:跳过?)第一次出现[0:0]? 我在这里误解了什么?

2 个答案:

答案 0 :(得分:1)

这个怎么样:

fgrep -q '*filter' file && tac file|awk '!f&&/\[0:0\]/{$0="FOO\n\n"$0;f=1}1'|tac
someline

someline

*filter

:INPUT ACCEPT [0:0]

:FORWARD ACCEPT [0:0]

:OUTPUT ACCEPT [0:0]

FOO

someline

fgrep中的固定字符串*filter的第一个file,如果找到,请在包含FOO的最后一行之后插入行[0:0]tac用于反向读取文件,因此您不需要读取文件两次或缓冲区以查找最后一次出现,因为它更容易找到第一次出现。


如果文件的大小不是很大,则使用awk

的两遍方法
awk 'FNR==NR{if($0~/*filter/)a=1;if(a&&$0~/\[0:0\]/)b=NR;next}FNR==b{$0=$0"\n\nFOO"}1' file file

someline

someline

*filter

:INPUT ACCEPT [0:0]

:FORWARD ACCEPT [0:0]

:OUTPUT ACCEPT [0:0]

FOO

someline

答案 1 :(得分:0)

sed以来略有不同的做法,对于换行线来说很糟糕......

基本上,我将所有内容放在一行中,用@替换换行符,使用贪婪匹配替换换行符,最后再将换行符放回...

$ cat input | tr '\n' '@' | sed s'/\(\*filter.*\[0:0\]\)/@@\1@TESTLINEADDEDBYSED/' | tr '@' '\n'
someline

someline


*filter

:INPUT ACCEPT [0:0]

:FORWARD ACCEPT [0:0]

:OUTPUT ACCEPT [0:0]

TESTLINEADDEDBYSED

someline

如果文件中的行数很大,这是一种糟糕的方法!