JSON配列の1つのフィールドをbash配列に解析する

JSON配列の1つのフィールドをbash配列に解析する

変数に格納されたオブジェクトのリストを含む JSON 出力があります。(表現が適切でない可能性があります)

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

Ubuntu 14.04.1 で bash スクリプトを実行するには、配列内の item2 のすべての値が必要です。

結果全体を配列に入れる方法はたくさんあるが、必要な項目だけを入れる方法はない

答え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評価するシェル ステートメントを生成するために使用します。

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

質問のJSONドキュメントを考えると、を呼び出すとjq文字列が生成されます。

arr=( 'value2' 'value2_2' )

これはシェルによって評価されます。その文字列を評価すると、arr2 つの要素value2とを含む名前付き配列が作成されますvalue2_2

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

演算子@shは、jqシェルのデータを適切に引用符で囲むように注意します。

あるいは、その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 にパイプすることだけです。うまく機能し、いくつかの手順を省くことができました。

関連情報