如何在通过参数传递它的函数中更新关联数组?

我有以下代码读取fieldsJson 文件的所有内容(路径是PRIVATE_REGISTRATION_FILE并将它们存储到PRIVATE_FIELDS我稍后在代码中查询的关联数组 ( ) 中:

declare -A PRIVATE_FIELDS
for PRICING_FIELD in $(jq -c -r '.fields[]' "${PRIVATE_REGISTRATION_FILE}")
do
  FIELD_KEY=$(jq -r '.label' <<< "${PRICING_FIELD}")
  PRIVATE_FIELDS["${FIELD_KEY}"]=${PRICING_FIELD}
done

问题是我对多个文件执行了多次此操作,即使逻辑始终相同。

因此,我想将这个逻辑提取到一个函数中,但我很难将 map 参数传递给它。

这是我尝试的:

function update_array
{
    FILE_NAME=$1
    eval "declare -A MAP="${2#*=}
    for PRICING_FIELD in $(jq -c -r '.fields[]' "${FILE_NAME}")
    do
        FIELD_KEY=$(jq -r '.label' <<< "${PRICING_FIELD}")
        MAP["${FIELD_KEY}"]=${PRICING_FIELD}
    done
}

我这样称呼它:

declare -A PRIVATE_FIELDS
update_array "myFile.json" "$(declare -p PRIVATE_FIELDS)"

但是它不起作用,地图仍然是空的。

echo ${PRIVATE_FIELDS["someKey"]}
>>> (empty)

我已经尝试了这个答案中提出的每个解决方案,但没有一个有效。我究竟做错了什么?

bash 版本: 4.2.46(2)-release


附加说明,Json 文件如下所示(显然对 的调用jq可能会减少):

{
    "name": "Something",
    "fields": [
        {
            "label": "key1",
            "value": "value1",
            "other": "other1"
        },
        {
            "label": "key2",
            "value": "value2",
            "other": "other2"
        }
    ]
}

回答

当您declare在函数中使用时,您实际上是在创建变量localhelp declare在 bash 提示符下查看。

使用 nameref(需要 bash 版本4.3 +):

function update_array
{
    local FILE_NAME=$1
    local -n MAP=$2     # MAP is now a _reference_ to the caller's variable
    # the rest stays the same
    for PRICING_FIELD in $(jq -c -r '.fields[]' "${FILE_NAME}")
    do
        FIELD_KEY=$(jq -r '.label' <<< "${PRICING_FIELD}")
        MAP["${FIELD_KEY}"]=${PRICING_FIELD}
    done
}

然后您只需传递数组名称

declare -A PRIVATE_FIELDS
update_array "myFile.json" PRIVATE_FIELDS

declare -p PRIVATE_FIELDS

要更有效地遍历 JSON 文件:

$ jq -c -r '.fields[] | "(.label)t(.)"' file.json
key1    {"label":"key1","value":"value1","other":"other1"}
key2    {"label":"key2","value":"value2","other":"other2"}

这是假设标签不包含任何制表符。


使用它,加上你的旧 bash 版本,你可以做到这一点

假设结果数组将在全局范围内

update_array() {
    local filename=$1 varname=$2
    local -A map
    while IFS=$'t' read -r label json; do
        map[$label]=$json
    done < <(
        jq -c -r '.fields[] | "(.label)t(.)"' "$filename"
    )
    eval declare -gA "$varname=$(declare -p map | cut -d= -f2-)"
}

你会这样称呼它

$ echo $BASH_VERSION
4.2.45(1)-release

$ update_array tmp/file.json myArray

$ declare -p myArray
declare -A myArray='([key2]="{"label":"key2","value":"value2","other":"other2"}" [key1]="{"label":"key1","value":"value1","other":"other1"}" )'

$ for label in "${!myArray[@]}"; do
>     printf '"%s" => >>%s<<n' "$label" "${myArray[$label]}"
> done
"key2" => >>{"label":"key2","value":"value2","other":"other2"}<<
"key1" => >>{"label":"key1","value":"value1","other":"other1"}<<

  • 改掉使用 ALLCAPS 变量名的习惯,将它们保留为 shell 保留。有一天你会写`PATH=something`然后[想知道为什么](/sf/ask/1928854231/)你的[脚本坏了](/sf/ask/19841/​​10594 /7552)。

以上是如何在通过参数传递它的函数中更新关联数组?的全部内容。
THE END
分享
二维码
< <上一篇
下一篇>>