Arrays bash将XML解析为多维数组

Arrays bash将XML解析为多维数组,arrays,xml,linux,bash,parsing,Arrays,Xml,Linux,Bash,Parsing,我有一个XML文件,我想将其解析为bash变量/数组。 由于我使用的是NAS设备,所以可用的linux命令(busybox)有限 我的XML文件如下所示: <?xml version="1.0" encoding="UTF-8"?> . <WEBCAMS> <CAM> <DESCRIPTION>description for cam 1</DESCRIPTION> <URL

我有一个XML文件,我想将其解析为bash变量/数组。 由于我使用的是NAS设备,所以可用的linux命令(busybox)有限

我的XML文件如下所示:

<?xml version="1.0" encoding="UTF-8"?> . 
<WEBCAMS>  
<CAM>  
            <DESCRIPTION>description for cam 1</DESCRIPTION>
            <URL>http://myURLtoWebcam1/cam1/pic.jpg</URL>
            <FILENAME>filename1</FILENAME>   
</CAM>  
<CAM>  
            <DESCRIPTION>description for cam 2</DESCRIPTION>
            <URL>http://myURLtoWebcam2/cam2/pic.jpg</URL>
            <FILENAME>filename2</FILENAME>   
</CAM>   
</WEBCAMS> 
到目前为止,我只能将“DESCRIPTION”字段读入bash变量。

知道如何将其他字段“URL”和“FILENAME”放入我的数组/变量中吗?由于我的NAS上的Linux命令有限,到目前为止找到的解决方案不适合我的需要,或者无法根据我的需要进行修改。

如果XSLTPROC可用,您可以使用它-这是一个真正的XML解析器

> xsltproc transform.xsl webcams.xml 

Cam1 description: description for cam 1
Cam1 URL: http://myURLtoWebcam1/cam1/pic.jpg
Cam1 filename: filename1
Cam2 description: description for cam 2
Cam2 URL: http://myURLtoWebcam2/cam2/pic.jpg
Cam2 filename: filename2
transform.xsl在哪里

<?xml version="1.0"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
  <xsl:output method="text" omit-xml-declaration="yes" indent="no"/>
  <xsl:strip-space elements="*"/>
  <xsl:template match="CAM">
  <xsl:variable name="i" select="position()" />
Cam<xsl:value-of select="$i"/> description: <xsl:value-of select="DESCRIPTION"/>
Cam<xsl:value-of select="$i"/> URL: <xsl:value-of select="URL"/>
Cam<xsl:value-of select="$i"/> filename: <xsl:value-of select="FILENAME"/>
  </xsl:template>


  <xsl:template match="/WEBCAMS"><xsl:apply-templates select="*"/>
  <xsl:text>
</xsl:text>
  </xsl:template>
</xsl:stylesheet>

凸轮说明:
Cam URL:
Cam文件名:

这似乎有效。。。但是,1,5D维数组或转义变量的方法仍然让我头疼——请参见下面FOR循环中的问题:

#!/bin/sh
rdom () { local IFS=\> ; read -d \< E C ;}
while rdom; do
if [[ $E = DESCRIPTION ]]; then
        counter0=$((counter0+1))
        declare -a cam$((counter0))[0]="$C"
fi

if [[ $E = URL ]]; then
        counter1=$((counter1+1))
        declare -a cam$((counter1))[1]="$C"
fi

if [[ $E = FILENAME ]]; then
        counter2=$((counter2+1))
        declare -a cam$((counter2))[2]="$C"
fi

done < webcams.xml

echo "Cam1 description: ${cam1[0]}";
echo "Cam1 URL: ${cam1[1]}";
echo "Cam1 filename: ${cam1[2]}";

echo "Cam2 description: ${cam2[0]}";
echo "Cam2 URL: ${cam2[1]}";
echo "Cam2 filename: ${cam2[2]}";
#/垃圾箱/垃圾箱
rdom(){local IFS=\>;read-d\
但仍然无法在FOR循环中获取值,如:

for (( c=1; c<=$counter0; c++ ))
do
        var=cam$c;
        echo "Cam$c description: ${!var[0]}";
        echo "Cam$c URL: ${!var[1]}";
        echo "Cam$c filename: ${!var[2]}";
done

for((c=1;cWait.您是有busybox外壳还是有bash?(
#!/bin/sh
通常类似于busybox在使用它的系统上实现了
ash
;即使在它是bash的符号链接的系统上,当作为
sh
调用时,它也会进入不那么有特色的POSIX模式)。如果您真的有bash,并且希望能够使用仅限bash的语法,那么您的shebang应该类似于
#!/bin/bash
。除此之外,您在该系统上还有哪些其他软件?在某个地方隐藏真正的XML解析器并不少见(在Python等解释语言运行库中,或通过libxml2等本机依赖项安装在shell可访问的帮助程序中)即使是在相当小的系统上。使用这种解析器的答案也不太容易出现错误(让集成合作伙伴在不应损害其代码中断的更改时中断手工编写的用户是非常烦人的,有这种经验的人往往对提出问题来糟糕地解析XML没有耐心)。顺便说一句,
IFS=\>read-d\
(没有分号或换行符)仅为one
read
命令的范围设置
IFS
;不需要尝试使用函数局部变量或类似的函数。我直到现在才看到您的注释,因为您将其放在其他人的答案上而不是这里--
rdom(){local IFS=\>;read-d\
试图将IFS定义为函数本地,但这是不必要的:您可以将IFS本地设置为单个
read
命令,只需取出
read
之间的
并删除
local
关键字。
var=val-somecommand
使用
var
t运行
somecommand
暂时在环境中导出为
val
。很抱歉在错误的位置添加我的注释,这让您感到困惑。现在我得到了您的提示。我将代码的第一行更改为
rdom(){IFS=\>read-d\
,效果很好。我正在使用GNU bash,3.2.57(1)版(i686 pc linux GNU)但是命令有限。不幸的是没有XML解析器。Charles你最近对我的IFS用法的评论是什么意思?特别是我不理解你的说法:“没有必要尝试使用函数局部变量之类的东西”如果我这样做,我会有一个描述数组、一个URL数组和一个文件名数组。这样你就可以轻松地让
for
循环。出于我的目的,我需要每个cam都有一个数组-每个数组包含3个字段:描述、URL和文件名。之后是cam的数量(数组)不同。CAM的数量不同听起来像是一个非常有说服力的理由,正好有三个数组,元素的数量不同,而不是相反。如果是这样,您可以这样做:${!descriptions[@]};do echo“description:${descriptions[$idx]},url:${url[$idx]};filename:${filenames[$idx]}
;done`--非常干净,非常简单。我更改了(为数组添加了eval)上面的for循环,毕竟它看起来也非常简单?
for((c=1;c)
#!/bin/sh
rdom () { local IFS=\> ; read -d \< E C ;}
while rdom; do
if [[ $E = DESCRIPTION ]]; then
        counter0=$((counter0+1))
        declare -a cam$((counter0))[0]="$C"
fi

if [[ $E = URL ]]; then
        counter1=$((counter1+1))
        declare -a cam$((counter1))[1]="$C"
fi

if [[ $E = FILENAME ]]; then
        counter2=$((counter2+1))
        declare -a cam$((counter2))[2]="$C"
fi

done < webcams.xml

echo "Cam1 description: ${cam1[0]}";
echo "Cam1 URL: ${cam1[1]}";
echo "Cam1 filename: ${cam1[2]}";

echo "Cam2 description: ${cam2[0]}";
echo "Cam2 URL: ${cam2[1]}";
echo "Cam2 filename: ${cam2[2]}";
for (( c=1; c<=$counter0; c++ ))
do
        var=cam$c;
        echo "Cam$c description: ${!var[0]}";
        echo "Cam$c URL: ${!var[1]}";
        echo "Cam$c filename: ${!var[2]}";
done