无法从Bash关联数组中检索键/值对

时间:2017-03-23 15:37:05

标签: linux bash shell

TL; DR

我无法从bash中的关联数组中检索键列表 脚本。但是,当我尝试编写简化的MCVE时,一切都是如此 按预期工作,我不知道我在两者之间做了什么不同。

长版

我正在编写一个bash脚本,需要从中读取一组首选项 一个文件并将它们存储在一个关联数组中。请注意,我正在使用XML和 我更喜欢使用Perl模块来读取文件,但脚本会 在大量系统上运行,其中大多数都没有正确的系统 安装了Perl模块,而且我几乎没有必要的模块 访问安装它们。无论如何,解析XML文件不是问题所在。

问题是,当我针对XML文件运行以下脚本时, 我正在从XML文件中读取的设置似乎正在保存到 关联数组。换句话说,以下代码按预期工作:

while read line
do
    # Trimming code that sets key-val.
    $config[$key]=$val
    echo "${key}=${config[$key]}"
done

但是后来我在脚本中试图检索配置值时,什么都没有 似乎在那里。似乎配置数组已被清除 不知何故,但我不清楚在哪里或如何。

xml_config.sh

这是非工作脚本。

#! /bin/bash

# Configuration Array.
declare -A config

CONFIG_XML=./config.xml

# Extract key-value pairs.
echo "Extracting and setting initial key-value pairs:"
grep "^.*<setting.*id=.*$" $CONFIG_XML |
while read line
do
    key=$(echo "${line}" | perl -pe "s|^.*id.*?=.*?[\'\"](.*?)[\'\"].*$|\1|")
    val=$(echo "${line}" | perl -pe "s|^.*value.*?=.*?[\'\"](.*?)[\'\"].*$|\1|")
    config[$key]="${val}"

    # This line prints key=value pairs as expected.
    echo "${key}=${config[$key]}"
done

# This loop does not print key=value pairs as expected.
echo -e "\n\nExtracting key-value pairs from associative array and printing:"
for key in "${!config[@]}"
do
    echo "${key}=${config[$key]}"
done

echo -e "\n\nAlso doesn't work:\nkey1=${config[key1]}"

config.xml中

这是与脚本一起提供的config.xml文件的内容:

<?xml version="1.0" encoding="UTF-8"?>
<config>
    <setting id="key1" value="val1" />
    <setting id="key2" value="val2" />
    <setting id="key3" value="val3" />
    <setting id="key4" value="val4" />
    <setting id="key5" value="val5" />
</config>

简化的MCVE

以下是我预期的简化MCVE的内容 失败,但是按预期工作:

declare -A aa
for i in {0..10}
do
    key="KEY${i}"
    val="VAL${i}"
    aa[$key]=$val
done

for key in "${!aa[@]}"
do
    # Prints key-value pairs as expected.
    echo "${key}=${aa[$key]}"
done

1 个答案:

答案 0 :(得分:2)

while循环必须在当前shell中执行才能使对数组的更改生效。一种解决方案是使用流程替换而不是管道。

while read line
do
    key=$(echo "${line}" | perl -pe "s|^.*id.*?=.*?[\'\"](.*?)[\'\"].*$|\1|")
    val=$(echo "${line}" | perl -pe "s|^.*value.*?=.*?[\'\"](.*?)[\'\"].*$|\1|")
    config[$key]="${val}"

    # This line prints key=value pairs as expected.
    echo "${key}=${config[$key]}"
done < <(grep "^.*<setting.*id=.*$" $CONFIG_X)

如果您使用的是bash 4.2或更高版本,则可以使用lastpipe选项。

shopt -s lastpipe

grep "^.*<setting.*id=.*$" $CONFIG_XML | while read line; do
    ...
done