如何更新通过参数传递的函数内的关联数组?
How can I update an associative array inside a function passing it by parameter?
我有以下代码读取 Json 文件的所有 fields
(路径为 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=
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)
我确实尝试了 in this answer 提出的每个解决方案,但其中 none 有效。我做错了什么?
Bash版本:4.2.46(2)-release
补充说明,Json 文件看起来像这样(显然可以减少对 jq
的调用):
{
"name": "Something",
"fields": [
{
"label": "key1",
"value": "value1",
"other": "other1"
},
{
"label": "key2",
"value": "value2",
"other": "other2"
}
]
}
当您在函数中使用 declare
时,您实际上是在将变量设为 local。在 bash 提示符下查看 help declare
。
使用名称引用(需要 bash 版本 4.3+):
function update_array
{
local FILE_NAME=
local -n MAP= # 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
}
然后你只需传递数组 name
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= varname=
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"}<<
我有以下代码读取 Json 文件的所有 fields
(路径为 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=
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)
我确实尝试了 in this answer 提出的每个解决方案,但其中 none 有效。我做错了什么?
Bash版本:4.2.46(2)-release
补充说明,Json 文件看起来像这样(显然可以减少对 jq
的调用):
{
"name": "Something",
"fields": [
{
"label": "key1",
"value": "value1",
"other": "other1"
},
{
"label": "key2",
"value": "value2",
"other": "other2"
}
]
}
当您在函数中使用 declare
时,您实际上是在将变量设为 local。在 bash 提示符下查看 help declare
。
使用名称引用(需要 bash 版本 4.3+):
function update_array
{
local FILE_NAME=
local -n MAP= # 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
}
然后你只需传递数组 name
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= varname=
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"}<<