如何使用 jq 中的键和值生成 bash 关联数组?

How can I use keys and values from jq to generate a bash associative array?

来自 Json 结构,我想要一个特定的字典。从键的颜色黄色或红色,我添加 id 值。

[
  {
    "id": "9b058640",
    "type": "db",
    "color": "red",
    "host": "db1"
  },
  {
    "id": "0u858640",
    "type": "db",
    "color": "yellow",
    "host": "db2"
  },
  {
    "id": "0ui9k40",
    "type": "net",
    "color": "red",
    "host": "net1"
  },
  {
    "id": "5ty87a",
    "type": "net",
    "color": "yellow",
    "host": "net2"
  }
]

所以我想获取 X 字典

X=(
   ['yellow']="9b058640 5ty87a"
   ['red']="9b058640 0ui9k40"
 )

我可以按值解析 :

jq -c '.[] | select(.color | contains("red"))'

您可以在 jq 中使用 @tsv 运算符来发出 tab-separated 输出,bash while read 循环可以轻松地将其解析为输入。

假设您的输入 JSON 在变量 s 中:

declare -A X=( )

while IFS=$'\t' read -r color id; do
  X[$color]+="$id "
done < <(jq -r '.[] | [.color, .id] | @tsv' <<<"$s")

上面确实走了一个小捷径,因为它在每个项目之后留下了尾随 space。如果出于某种原因这是不可接受的,您可以随时遍历数组并在事后使用第二个循环清理它:

for color in "${!X[@]}"; do
  X[$color]=${X[$color]%" "}
done

您可以在 https://replit.com/@CharlesDuffy2/IndigoRemoteEngineering

的沙箱中看到此 运行

或者,使用 eval:

#!/usr/bin/env bash
case $BASH_VERSION in ''|[0-3].*) echo "ERROR: bash 4.0+ required" >&2; exit 1;; esac
declare -A X=( )
eval "$(
  jq -r '
    reduce .[] as $item ({}; .[$item.color] += [$item.id])
    | to_entries[]
    | "X[\(.key | @sh)]=\(.value | join(" ") | @sh)"
  '
)" <file.json

答案:

declare -A a
. <(jq -r '"a[\(.color)]+=${a[\(.color)]+ }\(.id)"' file.json)

提供:

$ declare -p a
$ declare -A a=([red]="9b058640 0ui9k40" [yellow]="0u858640 5ty87a" )
# or
$ echo "${a[red]}"; echo "${a[yellow]}"
9b058640 0ui9k40
0u858640 5ty87a

解释:

  • jq中构造以下bash代码:
  • a[color]+=${a[color]+ }id
  • ${a[color]+ } 扩展为 ,仅当 a[color] 为空时。
  • "\(.id)" 是 jq 字符串插值 - 它被替换为 .id
  • 的值
  • 使用 . 和一个进程子来获取此代码

不需要 .sourceeval 甚至 bash 中的循环。您只需要 declarejq,它们可以使用 escaping with @sh and string interpolation:

构造声明
declare -A X="($(
  jq -r '
    ("yellow", "red") as $color 
    | @sh "[\($color)]=\(map(select(.color == $color).id) | join(" "))"
  ' input.json
))"
$ echo "${X[yellow]}"
0u858640 5ty87a

$ echo "${X[red]}"
9b058640 0ui9k40