json字典到使用readarray的bash哈希表



首先是一个使用数组的工作示例

json_array() {
local -n array="${1}"
readarray -d $'' -t array < <(
# Create nul delimited array entry using jq
jq -cjn --argjson arr "$array" '$arr|map(tostring)|.[]+"u0000"'
)
}
> unset arr; arr='["a", "b", "c"]'; json_array arr; echo "${arr[0]} ${arr[1]} ${arr[2]}"
a b c

现在我正在尝试对dict做一些类似的事情,将json dict转换为bash关联数组

json_dict() {
local -n dict="${1}"
declare -A hash_table
append_to_hash_table() {
shift
{ read -r key;  read -r value; } <<<"$1"
hash_table+=([$key]="$value")
}
readarray -d $'' -c 1 -C append_to_hash_table < <(
# Create nul delimited dict entry using jq
jq -cjn --argjson d "$dict" '$d|to_entries|map("(.key)n(.value|tostring|@sh)")|.[]+"u0000"'
)
# Here hash_table contain the correct output
dict=""
dict="$hash_table"
}
> unset arr; arr='{"a": "aa", "l": "bb", "c": "ccccc"}'; json_dict arr; echo "${arr[@]}"
Nothing

CCD_ 1似乎没有正确地更新refname,如何使bashdictrefname指向hash_table

这里不需要readarray:您可以将两个单独的NUL分隔的read作为while循环的一部分。

请参阅下面的答案https://replit.com/@CharlesDuffy2/GrandiosDraftyArguments#main.sh

while IFS= read -r -d '' key && IFS= read -r -d '' value; do
hash_table[$key]=$value
done < <(jq -cjn --argjson d "$arr" 
'$d | to_entries[] | ( .key, "u0000", .value, "u0000")')

将此放在上下文中:

json_dict() {
declare key value in_value="${!1}"
unset "$1"                   # FIXME: Better to take a $2 for output variable
declare -g -A "$1"
declare -n hash_table="$1"
while IFS= read -r -d '' key && IFS= read -r -d '' value; do
hash_table[$key]=$value
done < <(
jq -cjn --argjson d "$in_value" 
'$d | to_entries[] | ( .key, "u0000", .value, "u0000")'
)
}

arr='{"a": "aa", "l": "bb", "c": "ccccc"}'
json_dict arr
declare -p arr

作为输出发射:

declare -A arr=([a]="aa" [c]="ccccc" [l]="bb" )

也就是说,要完全按照要求回答问题,因此使用readarray:

json_dict() {
declare -a pieces=()
readarray -d '' pieces < <(
jq -cjn --argjson d "${!1}" 
'$d | to_entries[] | ( .key, "u0000", .value, "u0000")'
)
unset "$1"
declare -g -A "$1"
declare -n hash_table="$1"
set -- "${pieces[@]}"
while (( $# )); do
hash_table[$1]=$2
{ shift && shift; } || return
done
}
arr='{"a": "aa", "l": "bb", "c": "ccccc"}'
json_dict arr
declare -p arr

仅仅使用declare并让jq使用dict="$hash_table"0创建内容以实现shell一致性不是更简单吗?

索引数组:

unset arr; arr='["a", "b", "c"]'
declare -a arr="($(jq -r @sh <<< "$arr"))"

关联数组:

unset arr; arr='{"a": "aa", "l": "bb", "c": "ccccc"}'
declare -A arr="($(jq -r 'to_entries[] | @sh "[(.key)]=(.value)"' <<< "$arr"))"

响应编辑请求:上面要求值为字符串(数字和布尔值也可以(,但其他结构需要首先采用字符串格式。特别是,在请求之后,@json可以用于将任意JSON内容编码为字符串。但是,请记住,在这样做的过程中,bash数组的项将被JSON编码,这意味着简单的事例(如上面的aa等字符串(也将被编码(例如,根据JSON的要求,作为"aa",包括引号(。如果这是你想要的,那就去吧:

带JSON编码值的索引数组:

unset arr; arr='["a", {}, [null, {"a": true}]]'
declare -a arr="($(jq -r 'map(@json) | @sh' <<< "$arr"))"

具有JSON编码值的关联数组:

unset arr; arr='{"a": "aa", "b": {"l": "bb", "c": "ccccc"}}'
declare -A arr="($(jq -r 'to_entries[] | @sh "[(.key)]=(.value | @json)"' <<< "$arr"))"

最新更新