將 JSON 數組中的一個字段解析為 bash 數組

將 JSON 數組中的一個字段解析為 bash 數組

我有一個 JSON 輸出,其中包含儲存在變數中的物件列表。 (我的表述可能不太對)

[
  {
    "item1": "value1",
    "item2": "value2",
    "sub items": [
      {
        "subitem": "subvalue"
      }
    ]
  },
  {
    "item1": "value1_2",
    "item2": "value2_2",
    "sub items_2": [
      {
        "subitem_2": "subvalue_2"
      }
    ]
  }
]

我需要數組中 item2 的所有值才能在 ubuntu 14.04.1 上運行 bash 腳本。

我找到了很多方法將整個結果放入數組中,而不僅僅是我需要的項目

答案1

使用:

readarray arr < <(jq '.[].item2' json)
printf '%s\n' "${arr[@]}"

如果您需要更強化的方法:

readarray -td '' arr

對於帶有換行符或其他特殊字元的輸入,避免分詞。

輸出:

value2
value2_2

查看:

處理替換>(command ...)或被<(...)臨時檔案名稱替換。寫入或讀取該檔案會導致位元組透過管道傳輸到內部命令。通常與檔案重定向結合使用:cmd1 2> >(cmd2).看http://mywiki.wooledge.org/ProcessSubstitution http://mywiki.wooledge.org/BashFAQ/024

答案2

以下實際上是錯誤的:

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

如果您有 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")'
)

....而使用 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' )

...或 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'
)

...或 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")')

答案3

用於jq產生您評估的 shell 語句:

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

給定問題中的 JSON 文檔,呼叫jq將產生字串

arr=( 'value2' 'value2_2' )

然後由您的 shell 對其進行評估。計算該字串將建立arr包含兩個元素value2和 的命名陣列value2_2

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

運算子@shinjq會注意正確引用 shell 的資料。

或者,將該arr=( ... )部分移出jq表達式:

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

現在,jq僅產生引用的元素列表,然後將其插入arr=( ... )並求值。

如果需要從curl命令中讀取數據,請在上面的命令中使用curl ... | jq -r ...代替。jq -r ... file.json

答案4

感謝 sputnick 我得到了這個:

arr=( $(curl -k https://localhost/api | jq -r '.[].item2') )

我擁有的 JSON 是 API 的輸出。我所需要做的就是刪除檔案參數並將|curl 的輸出透過管道傳輸到jq。效果很好,節省了一些步驟。

相關內容