在循环中将变量添加到 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