awk / sed:在特定块号的最后一行之前插入文件内容

给定是两个文件,第一个是Apacheconfiguration文件:

$ cat vhosts-ssl.conf <VirtualHost *:443> vhost 1 foobar 1 foobar 2 barfoo 1 barfoo 2 </VirtualHost> <VirtualHost *:443> vhost 2 foobar 2 barfoo 1 foobar 1 barfoo 2 </VirtualHost> <VirtualHost *:443> vhost 3 foobar 1 barfoo 1 foobar 2 barfoo 2 </VirtualHost> <VirtualHost *:443> vhost 4 foobar 1 foobar 2 barfoo 1 barfoo 2 </VirtualHost> 

第二个文件包含应该添加到一个(可变)特定的VirtualHost块的末尾的行:

 $ cat inserted.txt inserted line 1 inserted line 2 

结果应该是这样的:

 $ cat vhosts-ssl.conf <VirtualHost *:443> vhost 1 foobar 1 foobar 2 barfoo 1 barfoo 2 </VirtualHost> <VirtualHost *:443> vhost 2 foobar 2 barfoo 1 foobar 1 barfoo 2 inserted line 1 inserted line 2 </VirtualHost> <VirtualHost *:443> vhost 3 foobar 1 barfoo 1 foobar 2 barfoo 2 </VirtualHost> <VirtualHost *:443> vhost 4 foobar 1 foobar 2 barfoo 1 barfoo 2 </VirtualHost> 

我尝试了以下sed的一些变化,但是这并没有诀窍:

 $ sed -e '/^<VirtualHost/{:a;n;/^<\/VirtualHost/\!ba;r inserted.txt' -e '}' vhosts-ssl.conf 

我无法弄清楚如何只select一个VirtualHost块我需要插入文件,因为我已经使用FreeBSD sed(或awk)我也得到这个错误与以前的sed命令:

 $ sed -e '/^<VirtualHost/{:a;n;/^<\/VirtualHost/\!ba;r inserted.txt' -e '}' vhosts-ssl.conf sed: 2: "} ": unused label 'a;n;/^<\/VirtualHost/!ba;r inserted.txt' 

用GNU sed我得到这个输出:

 $ gsed -e '/^<VirtualHost/{:a;n;/^<\/VirtualHost/\!ba;r inserted.txt' -e '}' vhosts-ssl.conf <VirtualHost *:443> vhost 1 foobar 1 foobar 2 barfoo 1 barfoo 2 </VirtualHost> inserted line 1 inserted line 2 <VirtualHost *:443> vhost 2 foobar 2 barfoo 1 foobar 1 barfoo 2 </VirtualHost> inserted line 1 inserted line 2 <VirtualHost *:443> vhost 3 foobar 1 barfoo 1 foobar 2 barfoo 2 </VirtualHost> inserted line 1 inserted line 2 <VirtualHost *:443> vhost 4 foobar 1 foobar 2 barfoo 1 barfoo 2 </VirtualHost> inserted line 1 inserted line 2 

正如我想了解我的错误,并从他们lern,我宁愿有一些解释的答案,甚至可能连接到rtfm,谢谢。

新增2016-10-16

伪代码:

 if BLOCK begins with /^<VirtualHost/ and ends with /^<\/VirtualHost/ and is the ${n-th} BLOCK in FILE_1 then insert content of FILE_2 before last line of ${n-th} BLOCK without touching rest of FILE_1 endif save modified FILE_1 

$ {n-th}通过以下方式收集:

 $ httpd -t -D DUMP_VHOSTS | \ grep -i "${SUBDOMAIN}.${DOMAIN}" | \ awk '/^[^\ ]*:443[\ ]*/ {print $3}' | \ sed -e 's|(\(.*\))|\1|' | \ cut -d: -f2 

输出是我想通过FILE_2扩展的BLOCK的编号

并且请只有非GNU版本,因为我在FreeBSD上,谢谢。

Solutions Collecting From Web of "awk / sed:在特定块号的最后一行之前插入文件内容"

awk来拯救!

需要多char记录分隔符,由gawk支持

 $ awk 'NR==FNR{insert=$0; next} {print $0 (FNR==2?insert:"") RT}' RS='^$' insert.file RS="</VirtualHost>" file 

读取完成的第一个文件并分配给变量插入,同时在第二个记录结束时迭代第二个文件,在记录内容之后打印变量。

awk另一个版本

 $ awk 'NR==FNR{insert=insert?insert ORS $0:$0; next} /<\/VirtualHost>/ && ++c==2{print insert} 1' insert.file file 

在GNU sed (和BusyBox sed )中, abcirtw:命令之后的文件/ label / text可以用分号分隔,而在其他版本的sed ,文件/标签/文本只能由换行符分隔。

这种行为意味着,而不是定义标签a ,第一个字符串定义的标签
a;n;/^<\/VirtualHost/\!ba;r inserted.txt ,和-e括号分别使用-e一样,脚本必须在标签和分支之后分开。
(也!不能逃脱)

 sed -e '/^<VirtualHost/{:a' -e 'n;/^<\/VirtualHost/!ba' \ -e 'r inserted.txt' -e '}' vhosts-ssl.conf 

或者,脚本可以跨越多行:

 sed '/^<VirtualHost/ { :a n /^<\/VirtualHost/!ba r inserted.txt }' vhosts-ssl.conf 

请注意,这种拆分可能不适用于换行符必须转义的情况。 例如,使用aci命令时。

鉴于:

 $ cat f1.txt line 1 line 2 line 3 INSERT HERE line 4 line 5 $ cat f2.txt INSERTED LINE 1 INSERTED LINE 2 

你可以做:

 $ awk 'BEGIN{fc=""} FNR==NR{fc=fc $0 "\n";next} /^INSERT HERE/{printf "%s", fc; next} 1' f2.txt f1.txt line 1 line 2 line 3 INSERTED LINE 1 INSERTED LINE 2 line 4 line 5