【问题标题】:Content of array in bash is OK when called directly, but lost when called from functionbash中数组的内容直接调用时可以,但是从函数调用时会丢失
【发布时间】:2014-11-27 20:45:15
【问题描述】:

我正在尝试使用 xmllint 来搜索一个 xml 文件并将我需要的值存储到一个数组中。这是我正在做的事情:

#!/bin/sh

function getProfilePaths {
    unset profilePaths
    unset profilePathsArr
    profilePaths=$(echo 'cat //profiles/profile/@path' | xmllint --shell file.xml | grep '=' | grep -v ">" | cut -f 2 -d "=" | tr -d \")
    profilePathsArr+=( $(echo $profilePaths))
    return 0
}

在我的另一个功能中:

function useProfilePaths {
    getProfilePaths
    for i in ${profilePathsArr[@]}; do
    echo $i
    done
    return 0
}

useProfilePaths

无论我是在命令行上手动执行命令还是从不同的函数调用它们作为包装脚本的一部分,函数的行为都会发生变化。当我可以从包装脚本中执行函数时,数组中的项目为 1,与我从命令行执行时相比,它是 2:

$ echo ${#profilePathsArr[@]}
2

回显时profilePaths的内容是这样的:

$ echo ${profilePaths}
/Profile/Path/1 /Profile/Path/2

我不确定 xmllint 调用的分隔符是什么。

当我从包装脚本调用函数时,for 循环的第一次迭代的内容如下所示:

for i in ${profilePathsArr[@]}; do
    echo $i
done

第一个回声看起来像:

/Profile/Path/1
/Profile/Path/2

...第二个回显是空的。

谁能帮我调试这个问题?如果我能找出 xmllint 使用的分隔符是什么,也许我可以正确解析数组中的项目。

仅供参考,我已经尝试过以下方法,结果相同:

profilePaths=($(echo 'cat //profiles/profile/@path' | xmllint --shell file.xml | grep '=' | grep -v ">" | cut -f 2 -d "=" | tr -d \"))

【问题讨论】:

  • 这里有什么问题?该循环确实遍历了两个数组元素。请发布一个不引用本地文件的完整脚本(以便我们可以在我们的机器上运行它),并清楚地解释为什么输出异常。

标签: arrays bash shell loops ifs


【解决方案1】:

您应该使用正确的--xpath 开关,而不是使用--shell 开关和许多管道。

但据我所知,当您有多个值时,没有简单的方法可以拆分不同的节点。

所以一个解决方案是像这样迭代:

profilePaths=(
    $(
        for i in {1..100}; do
            xmllint --xpath "//profiles[$i]/profile/@path" file.xml || break
        done
    )
)

或使用:

profilePaths=( $(xmlstarlet sel -t -v "//profiles/profile/@path" file.xml) )

默认情况下它会使用换行符显示输出

【讨论】:

    【解决方案2】:

    您遇到的问题与数据封装有关;具体来说,函数中定义的变量是本地的,因此除非您另外定义它们,否则您无法在该函数之外访问它们。

    根据您正在使用的sh 的实现,您可以通过在变量定义上使用eval 或使用globalmkshdeclare -g 等修饰符来解决此问题。 987654326@ 和bash。我知道mksh 的实现肯定有效。

    【讨论】:

      【解决方案3】:

      感谢您提供有关如何解决此问题的反馈。在进行了更多调查后,我能够通过更改迭代“profilePaths”变量内容以将其值插入“profilePathsArr”数组的方式来完成这项工作:

      # Retrieve the profile paths from file.xml and assign to 'profilePaths'
      profilePaths=$(echo 'cat //profiles/profile/@path' | xmllint --shell file.xml | grep '=' | grep -v ">" | cut -f 2 -d "=" | tr -d \")
      
      # Insert them into the array 'profilePathsArr'
      IFS=$'\n' read -rd '' -a profilePathsArr <<<"$profilePaths"
      

      由于某种原因,我的主脚本调用了所有不同的函数并调用了其他脚本,因此分隔符似乎在此过程中丢失了。我无法找到根本原因,但我知道通过使用 "\n" 作为 IFS 和 while 循环,它就像一个魅力。

      如果有人希望在此添加更多 cmets,我们非常欢迎。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2021-03-06
        • 2012-12-07
        • 1970-01-01
        • 2017-02-22
        • 2021-12-10
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多