我有一个包含许多子目录的目录,每个子目录包含一个我要编辑的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.
在匹配特定行的第一个实例../jobs/foo*/config.xml
之后,我需要一种将多行文本插入到多个<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>
每个../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>' {} \;
但偶尔,<description>
中的长config.xml
文本会导致插入时出现不可预测的行号。
接下来,我尝试使用sed
搜索<properties>
的第一个实例,并在其后插入,例如
sed -i '0,/properties/a test' config.xml
但这导致在每行之后添加test
测试,直到找到<properties>
。使用sed -i '1,/
有相似的结果。真丑。
我不确定是否在此Amazon Linux机器上正确使用了sed
,并认为awk
在这里可能会更好。有人可以协助吗?谢谢。
答案 0 :(得分:1)
使用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
答案 1 :(得分:1)
假设要插入的文本位于名为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
文件位于运行此命令的目录中。
您的命令似乎几乎是正确的,除了您没有在范围内嵌套第二个地址以确保添加仅发生一次。
答案 2 :(得分:1)
关注我的评论并给出答案:
输入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 {} +