具有多个文件的heredoc内的变量

具有多个文件的heredoc内的变量

我有一个带有 xml 内容的 Heredoc,我添加了另一个文件的内容,如下所示:

bar文件:

<bar>
  $baz
</bar>

剧本:

bar=$(cat bar.xml)

# this would be the ideal, of course it doesn't work
baz=$(cat baz.xml)
#

cat << EOF > out.xml
<foo>
  $bar
</foo>
EOF

的输出out.xml

<foo>
  <bar>
    $baz
  </bar>
</foo>

现在我想将第三个文件添加到以下内容中bar

baz文件:

<baz>baz<baz>

所以最终的内容out.xml是:

<foo>
  <bar>
    <baz>baz</baz>
  </bar>
</foo>

该工作流程假设我可以将(一个大的)xml 文件剥离为组件,每个组件都有自己的组件。

master (heredoc) xml
  ^^^
  second xml
    ^^^
    third xml

我不知道从哪里开始,因为我想让它尽可能简单,所以任何帮助表示赞赏。

答案1

组合 XML 文档的惯用方法是使用XSLT。首先,一些设置:

$ cd "$(mktemp --directory)"
$ echo '<foo/>' > ./foo.xml
$ echo '<bar/>' > ./bar.xml
$ echo '<baz/>' > ./baz.xml

然后我们创建一个 XSLT 文件,它将一个文件的内容插入到源文件中的一个元素中,并按原样复制文件的其余部分:

$ cat > ./insert.xslt <<'EOF'
> <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
>     <xsl:template match="@* | node()">
>         <xsl:copy>
>             <xsl:apply-templates select="@* | node()"/>
>             <xsl:if test="name() = $element">
>                 <xsl:copy-of select="document($file)"/>
>             </xsl:if>
>         </xsl:copy>
>     </xsl:template>
> </xsl:stylesheet>
> EOF

现在我们可以将任意文件插入到另一个文件中:

$ xsltproc --output ./bar-insert.xml --stringparam file ./baz.xml --stringparam element bar ./insert.xslt ./bar.xml
$ cat ./bar-insert.xml
<?xml version="1.0"?>
<bar><baz/></bar>

让我们重复创建最终文件:

$ xsltproc --output ./foo-insert.xml --stringparam file ./bar-insert.xml --stringparam element foo ./insert.xslt ./foo.xml
$ cat ./foo-insert.xml
<?xml version="1.0"?>
<foo><bar><baz/></bar></foo>

这样做的好处是它可以处理任何 XML 文件,无论它们是否缩进,是否折叠空元素,等等。


如果多次引用该文件,它甚至会多次插入该文件。例如,给定 people.xml:

<people>
    <managers>
        <name>Jane Doe</name>
        <reports>
            <insert/>
        </reports>
    </managers>
    <interns>
        <insert/>
    </interns>
</people>

和插入.xml:

<name>Abe Lincoln</name>

我们现在可以轻松地将 insert.xml 放在这两个位置:

$ xsltproc --stringparam file ./insert.xml --stringparam element insert ./insert.xslt ./people.xml 
<?xml version="1.0"?>
<people>
    <managers>
        <name>Jane Doe</name>
        <reports>
            <insert><name>Abe Lincoln</name></insert>
        </reports>
    </managers>
    <interns>
        <insert><name>Abe Lincoln</name></insert>
    </interns>
</people>

答案2

你可以envsubst在这里使用:

bar=$(baz=$(cat baz.xml) envsubst '$baz' < bar.xml) envsubst '$bar' << 'EOF'
<foo>
  $bar
</foo>
EOF

这将确保只有$bar// ${bar}/被扩展,而不是其他扩展(, , , ...)或其他变量$baz,例如:${baz}$(cmd)`cmd`$((arith))${x#y}

bar=$(cat bar.xml)
baz=$(cat baz.xml)
eval "cat << EOF
<foo>
  $bar
</foo>
EOF"

方法。

答案3

我找到了这个解决方案,不知道是否有更好的解决方案:

sed -i '/<bar>/r baz.xml' bar.xml

然后是定界符:

bar=$(cat bar.xml)

cat << EOF > out.xml
<foo>
  $bar
</foo>
EOF

输出所需的结果:

<foo>
  <bar>
    <baz>baz</baz>
  </bar>
</foo>

相关内容