将 JSON 数组中的一个字段解析为 bash 数组

Jpa*_*WPD 23 bash ubuntu array shell-script json

我有一个 JSON 输出,其中包含存储在变量中的对象列表。(我可能措辞不对)

[
  {
    "item1": "value1",
    "item2": "value2",
    "sub items": [
      {
        "subitem": "subvalue"
      }
    ]
  },
  {
    "item1": "value1_2",
    "item2": "value2_2",
    "sub items_2": [
      {
        "subitem_2": "subvalue_2"
      }
    ]
  }
]
Run Code Online (Sandbox Code Playgroud)

我需要数组中 item2 的所有值,以便在 ubuntu 14.04.1 上运行 bash 脚本。

我找到了很多方法来将整个结果放入一个数组中,而不仅仅是我需要的项目

Gil*_*not 26

使用

$ cat json
[
  {
    "item1": "value1",
    "item2": "value2",
    "sub items": [
      {
        "subitem": "subvalue"
      }
    ]
  },
  {
    "item1": "value1_2",
    "item2": "value2_2",
    "sub items_2": [
      {
        "subitem_2": "subvalue_2"
      }
    ]
  }
]
Run Code Online (Sandbox Code Playgroud)

代码:

arr=( $(jq -r '.[].item2' json) )
printf '%s\n' "${arr[@]}"
Run Code Online (Sandbox Code Playgroud)

输出:

value2
value2_2
Run Code Online (Sandbox Code Playgroud)

  • 很棒的 `jq` 命令,但请不要将命令输出解析为带有 `arr=( $(...) )` 的数组(即使它恰好适用于示例输入):它无法按预期工作带有嵌入或前导/尾随空格,并可能导致意外的通配符。 (5认同)
  • `jq。<<< "$json"` 它与 shell (bash) 相关,非特定于 `jq` (2认同)
  • @GillesQuenot,...您是否愿意接受将 shell 端修复为不依赖分词,或明确设置 IFS 并禁用通配符以使分词可靠的编辑? (2认同)

Cha*_*ffy 8

以下实际上是错误的:

# BAD: Output line of * is replaced with list of local files; can't deal with whitespace
arr=( $( curl -k "$url" | jq -r '.[].item2' ) )
Run Code Online (Sandbox Code Playgroud)

如果您有 bash 4.4 或更高版本,则可以使用世界上最好的选项:

# BEST: Supports bash 4.4+, with failure detection and newlines in data
{ readarray -t -d '' arr && wait "$!"; } < <(
  set -o pipefail
  curl --fail -k "$url" | jq -j '.[].item2 | (., "\u0000")'
)
Run Code Online (Sandbox Code Playgroud)

...而使用 bash 4.0,您可以以失败检测和文字换行支持为代价获得简洁:

# OK (with bash 4.0), but can't detect failure and doesn't support values with newlines
readarray -t arr < <(curl -k "$url" | jq -r '.[].item2' )
Run Code Online (Sandbox Code Playgroud)

...或 bash 3.x 兼容性和故障检测,但不支持换行:

# OK: Supports bash 3.x; no support for newlines in values, but can detect failures
IFS=$'\n' read -r -d '' -a arr < <(
  set -o pipefail
  curl --fail -k "$url" | jq -r '.[].item2' && printf '\0'
)
Run Code Online (Sandbox Code Playgroud)

...或 bash 3.x 兼容性和换行支持,但没有故障检测:

# OK: Supports bash 3.x and supports newlines in values; does not detect failures
arr=( )
while IFS= read -r -d '' item; do
  arr+=( "$item" )
done < <(curl --fail -k "$url" | jq -j '.[] | (.item2, "\u0000")')
Run Code Online (Sandbox Code Playgroud)


Kus*_*nda 5

用于jq生成您评估的 shell 语句:

eval "$( jq -r '@sh "arr=( \([.[].item2]) )"' file.json )"
Run Code Online (Sandbox Code Playgroud)

给定问题中的 JSON 文档,调用jq将生成字符串

arr=( 'value2' 'value2_2' )
Run Code Online (Sandbox Code Playgroud)

然后由您的 shell 对其进行评估。arr计算该字符串将创建包含两个元素value2和的命名数组value2_2

$ eval "$( jq -r '@sh "arr=( \([.[].item2]) )"' file.json )"
$ printf '"%s"\n' "${arr[@]}"
"value2"
"value2_2"
Run Code Online (Sandbox Code Playgroud)

运算@sh符 injq会注意正确引用 shell 的数据。

或者,将该arr=( ... )部分移出表达式jq

eval "arr=( $( jq -r '@sh "\([.[].item2])"' file.json ) )"
Run Code Online (Sandbox Code Playgroud)

现在,jq仅生成引用的元素列表,然后将其插入arr=( ... )并求值。

如果需要从curl命令中读取数据,请在上面的命令中使用curl ... | jq -r ...代替。jq -r ... file.json