在循环中将变量添加到 bash 数组
Add variables to a bash array in a loop
我有一个包含键和值的 json 文件,我想将其添加到 bash 数组,但我无法使其工作。
1。使用数据
创建 JSON-文件
# JSON file
echo '{"persons": [{"name":"John", "age":30, "car":"big"}, {"name":"Alice", "age":29, "car":"big"}]}' > my.json
2。遍历姓名和年龄
# Looping over JSON
jq -c '.persons[]' my.json | while read p;
do
name=$(echo $p | jq -r '.name')
age=$(echo $p | jq -r '.age')
echo "Name: $name"
echo "Age: $age"
done
姓名和年龄按预期打印出来。
3。手动将姓名和年龄添加到数组
# Creating array and adding elements
declare -A mylookup
key="James"
value="31"
mylookup[$key]=$value
4。检查是否添加了值
for key in "${!mylookup[@]}"
do
echo "Key: $key"
echo "Value: ${lookup[$value]}"
done
奇怪的是我只正确显示了密钥
5。在循环中将姓名和年龄添加到数组
# Creating array and adding elements
declare -A mylookup
jq -c '.persons[]' my.json | while read p;
do
name=$(echo $p | jq -r '.name')
age=$(echo $p | jq -r '.age')
mylookup[$name]=$age
done
6.打印出 Array
中的键和值
现在我检查添加到数组中的内容。
for key in "${!mylookup[@]}"
do
echo "Key: $key"
echo "Value: ${lookup[$value]}"
done
什么都没有打印出来.....我哪里失败了?我怀疑在将键和值添加到数组时出现问题,但我找不到问题所在。
数组值正在丢失,因为您在这里使用了管道。由于 while 循环在分叉的 sub-shell 中是 运行,因此所有变量仅在分叉的子 shell 中设置,并且您在父 shell 中看不到任何变化。
您可以使用它来避免这种情况:
declare -A mylookup
while IFS=$'\t' read n a; do
mylookup[$n]="$a"
done < <(jq -r '.persons[] | "\(.name)\t\(.age)"' my.json)
# check array content
declare -p mylookup
declare -A mylookup=([Alice]="29" [John]="30" )
< <(...)
是 process substitution
通常的方法是让jq
输出一种shell可以准确读取的格式。这是无损 TSV 格式的示例:
#!/bin/bash
declare -A mylookup
while IFS=$'\t' read -r name age
do
printf -v name '%b' "$name"
printf -v age '%b' "$age"
mylookup["$name"]=$age
done < <(
echo '{"persons": [{"name":"John", "age":30, "car":"big"}, {"name":"Alice", "age":29, "car":"big"}]}' |
jq -r '.persons[] | [ .name, .age ] | @tsv'
)
declare -p mylookup
#=> mylookup='([Alice]="29" [John]="30" )'
备注: printf -v ... '%b' ...
是为了对 TSV 值进行转义;在你的情况下它们可能是不必要的
或者,您可以使用 jq
为 Bash 的 declare -A
语句输出有效的 bash 语法。
通过在 jq
中进行适当的 @sh
过滤,可以确保 JSON 数据不会发生无效或意外执行。
此方法节省了 shell 次非常低效的迭代。
#!/usr/bin/env bash
json_file=my.json
if dyn_declare=$(
jq --raw-output '"(",(.persons[]|"["+(.name|@sh)+"]="+(.age|@sh)),")"' \
"$json_file"
) && declare -A mylookup=$dyn_declare; then
# Do something useful with the populated associative array
# Here we just dump it for debug/demo purpose
declare -p mylookup
else
printf 'Could not parse %s into an associative array\n' \
"$json_file" >&2
exit 1
fi
我有一个包含键和值的 json 文件,我想将其添加到 bash 数组,但我无法使其工作。
1。使用数据
创建 JSON-文件# JSON file
echo '{"persons": [{"name":"John", "age":30, "car":"big"}, {"name":"Alice", "age":29, "car":"big"}]}' > my.json
2。遍历姓名和年龄
# Looping over JSON
jq -c '.persons[]' my.json | while read p;
do
name=$(echo $p | jq -r '.name')
age=$(echo $p | jq -r '.age')
echo "Name: $name"
echo "Age: $age"
done
姓名和年龄按预期打印出来。
3。手动将姓名和年龄添加到数组
# Creating array and adding elements
declare -A mylookup
key="James"
value="31"
mylookup[$key]=$value
4。检查是否添加了值
for key in "${!mylookup[@]}"
do
echo "Key: $key"
echo "Value: ${lookup[$value]}"
done
奇怪的是我只正确显示了密钥
5。在循环中将姓名和年龄添加到数组
# Creating array and adding elements
declare -A mylookup
jq -c '.persons[]' my.json | while read p;
do
name=$(echo $p | jq -r '.name')
age=$(echo $p | jq -r '.age')
mylookup[$name]=$age
done
6.打印出 Array
中的键和值现在我检查添加到数组中的内容。
for key in "${!mylookup[@]}"
do
echo "Key: $key"
echo "Value: ${lookup[$value]}"
done
什么都没有打印出来.....我哪里失败了?我怀疑在将键和值添加到数组时出现问题,但我找不到问题所在。
数组值正在丢失,因为您在这里使用了管道。由于 while 循环在分叉的 sub-shell 中是 运行,因此所有变量仅在分叉的子 shell 中设置,并且您在父 shell 中看不到任何变化。
您可以使用它来避免这种情况:
declare -A mylookup
while IFS=$'\t' read n a; do
mylookup[$n]="$a"
done < <(jq -r '.persons[] | "\(.name)\t\(.age)"' my.json)
# check array content
declare -p mylookup
declare -A mylookup=([Alice]="29" [John]="30" )
< <(...)
是 process substitution
通常的方法是让jq
输出一种shell可以准确读取的格式。这是无损 TSV 格式的示例:
#!/bin/bash
declare -A mylookup
while IFS=$'\t' read -r name age
do
printf -v name '%b' "$name"
printf -v age '%b' "$age"
mylookup["$name"]=$age
done < <(
echo '{"persons": [{"name":"John", "age":30, "car":"big"}, {"name":"Alice", "age":29, "car":"big"}]}' |
jq -r '.persons[] | [ .name, .age ] | @tsv'
)
declare -p mylookup
#=> mylookup='([Alice]="29" [John]="30" )'
备注: printf -v ... '%b' ...
是为了对 TSV 值进行转义;在你的情况下它们可能是不必要的
或者,您可以使用 jq
为 Bash 的 declare -A
语句输出有效的 bash 语法。
通过在 jq
中进行适当的 @sh
过滤,可以确保 JSON 数据不会发生无效或意外执行。
此方法节省了 shell 次非常低效的迭代。
#!/usr/bin/env bash
json_file=my.json
if dyn_declare=$(
jq --raw-output '"(",(.persons[]|"["+(.name|@sh)+"]="+(.age|@sh)),")"' \
"$json_file"
) && declare -A mylookup=$dyn_declare; then
# Do something useful with the populated associative array
# Here we just dump it for debug/demo purpose
declare -p mylookup
else
printf 'Could not parse %s into an associative array\n' \
"$json_file" >&2
exit 1
fi