【问题标题】:awk/sed: Insert file content before last line of specific block numberawk/sed:在特定块号的最后一行之前插入文件内容
【发布时间】:2017-02-25 05:39:21
【问题描述】:

有两个文件,第一个是 Apache 配置文件:

$ 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

我无法弄清楚如何只选择一个我需要将文件插入到的 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

由于我想了解我的错误并从中吸取教训,我希望得到一些解释的答案,甚至可能是一些指向 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 上,谢谢。

【问题讨论】:

  • 我添加了一些伪代码

标签: shell unix awk sed freebsd


【解决方案1】:

awk 来救援!

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

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

完整读取第一个文件并分配给变量insert,同时在第二个记录末尾迭代第二个文件打印记录内容之后的变量。

普通awk的另一个版本

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

【讨论】:

  • @karakfa...上次我看到你的代表你有 1,500 是一年前的......你==awkist!......很好的答案..lol
  • 好的,完全按照我的需要工作,但正如你所说的,只有 gawk。
  • FreeBSD awk 需要这个。
  • 第二个版本做到了。现在我要阅读更多关于 awk 的内容,它似乎比 sed 更强大。谢谢。
【解决方案2】:

给定:

$ 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

【讨论】:

  • 很好,但我没有任何东西可以用作“在此处插入”,请参阅我发布的 vhosts-ssl.conf 和新添加的伪代码。
【解决方案3】:

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

这种行为意味着第一个字符串不是定义标签a,而是定义标签
a;n;/^&lt;\/VirtualHost/\!ba;r inserted.txt,就像单独使用-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 命令时。

【讨论】:

  • 感谢标签行为差异的解释。
猜你喜欢
  • 2011-09-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-05-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多