繁体   English   中英

如何在多个文件的第一个匹配模式之后使用awk插入多行

[英]How to use awk to insert multiple lines after first match of a pattern, in multiple files

我有一个包含许多子目录的目录,每个子目录包含我要编辑的config.xml文件。 喜欢:

../jobs/foo_bar-v1.2_west/config.xml
../jobs/foo_bar-v1.3_west/config.xml
../jobs/foo_stuff-v1.3_east/config.xml
../jobs/foo_foo-v9.8_north/config.xml
../jobs/NOT_FOO-v0.1_whatev/config.xml
etc.

在匹配特定行的第一个实例<properties>之后,我需要一种将多行文本插入到多个../jobs/foo*/config.xml文件中的方法。

要插入的文本如下所示:

    <a.bunch.of.TextGoesHere>
      <permission>one.foo.Items.Foo:person.name</permission>
      <permission>two.foo.Items.Foo:person.name</permission>
      <permission>three.foo.Items.Foo:person.name</permission>
    </a.bunch.of.TextGoesHere>

每个../jobs/foo*/config.xml如下所示:

<?xml version='1.0' encoding='UTF-8'?>
<foo1>
  <actions/>
  <description>foo2</description>
  <keepDependencies>false</keepDependencies>
  <properties>
    <foo3/>
  </properties>
 ...
  <lots_of_other_stuff>
  <properties>
    <junk>
  </properties>

每个config.xml最终输出应如下所示:

<?xml version='1.0' encoding='UTF-8'?>
<foo1>
  <actions/>
  <description>foo2</description>
  <keepDependencies>false</keepDependencies>
  <properties>
    <a.bunch.of.TextGoesHere>
      <permission>one.foo.Items.Foo:person.name</permission>
      <permission>two.foo.Items.Foo:person.name</permission>
      <permission>three.foo.Items.Foo:person.name</permission>
    </a.bunch.of.TextGoesHere>
    <foo3/>
  </properties>
 ...
  <lots_of_other_stuff>
  <properties>
    <junk>
  </properties>

我尝试使用sed在特定行之后插入,例如

#!/bin/bash
find ../jobs/run* -name config.xml -exec sed -i '6a\
<text to insert>' {} \;

但是偶尔, config.xml中的长<description>文本会导致插入时出现不可预测的行号。

接下来,我尝试使用sed搜索<properties>的第一个实例,然后在其后插入,例如

sed -i '0,/properties/a test' config.xml

但这导致在每一行之后添加test测试,直到找到<properties> 使用sed -i '1,/具有相似的结果。 真丑。

我不确定我是否在此Amazon Linux机器上正确使用sed ,并认为awk在这里可能会更好。 有人可以协助吗? 谢谢。

使用GNU awk进行就地编辑时,您所需要做的就是:

awk -i inplace '
NR==FNR { text = (NR>1 ? text ORS : "") $0 }
FNR==1 { cnt=0 }
{ print }
/<properties>/ && !cnt++ { print text }
' file_containing_text_to_insert ../jobs/foo*/config.xml 

假设要插入的文本在一个名为insert的文件中:

sed -e '0,/<properties>/{/<properties>/r insert' -e '}' config.xml

r命令读取文件并将其附加在当前行之后;

0,/pattern/{/pattern/r filename}

确保仅pattern的第一个实例会附加文本。 由于命令必须在r读取文件名之后结束,因此必须使用-e将其分为两部分。

要就地编辑文件,请使用sed -i (对于GNU sed)。

要对多个文件执行此操作,可以使用find

find jobs -name 'config.xml' \
    -exec sed -i -e '0,/<properties>/{/<properties>/r insert' -e '}' {} +

这要求insert文件位于运行此命令的目录中。


您的命令看起来几乎是正确的,除了您没有在范围内嵌套第二个地址以确保追加仅发生一次。

跟进我的评论并给出答案:

输入的xml文件“ file.xml”

<?xml version='1.0' encoding='UTF-8'?>
<foo1>
  <actions/>
  <description>foo2</description>
  <keepDependencies>false</keepDependencies>
  <properties>
    <foo3/>
  </properties>
 ...
  <lots_of_other_stuff />
  <properties>
    <junk />
  </properties>
</foo1>

xslt样式表“ file.xslt”

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
    <!-- Identity transform -->
    <xsl:template match="@* | node()">
        <xsl:copy>
            <xsl:apply-templates select="@* | node()"/>
        </xsl:copy>
    </xsl:template>
    <!-- insert the new stuff before the first child of the first properties element -->
    <xsl:template match="/foo1/properties[1]/*[1]">
        <a.bunch.of.TextGoesHere>
            <permission>one.foo.Items.Foo:person.name</permission>
            <permission>two.foo.Items.Foo:person.name</permission>
            <permission>three.foo.Items.Foo:person.name</permission>
        </a.bunch.of.TextGoesHere>
        <xsl:copy-of select="."/>
   </xsl:template>
</xsl:stylesheet>

结果,使用

$ xmlstarlet transform file.xslt file.xml 
<?xml version="1.0"?>
<foo1>
  <actions/>
  <description>foo2</description>
  <keepDependencies>false</keepDependencies>
  <properties>
    <a.bunch.of.TextGoesHere><permission>one.foo.Items.Foo:person.name</permission><permission>two.foo.Items.Foo:person.name</permission><permission>three.foo.Items.Foo:person.name</permission></a.bunch.of.TextGoesHere><foo3/>
  </properties>
 ...
  <lots_of_other_stuff/>
  <properties>
    <junk/>
  </properties>
</foo1>

应用于所有文件:

find . -name config.xml -exec sh -c '
    for xmlfile; do
        xmlstarlet transform xform.xslt "$xmlfile" > "$xmlfile".new &&
        ln "$xmlfile" "$xmlfile".bak &&
        mv "$xmlfile".new "$xmlfile"
    done
' sh {} +

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM