arrays - 追加 - bash 配列



JSONオブジェクトをBash連想配列に変換する (4)

Bashスクリプトがあります。 JSONでデータを取得します。 JSON配列をBash配列に変換する必要があります。

{
  "SALUTATION": "Hello world",
  "SOMETHING": "bla bla bla Mr. Freeman"
}

Bashでは、この echo ${arr[SOMETHING]} ような値を取得します。


Answer #1

JSONオブジェクトを(bashでループを使用せずに)bash連想配列に効率的にロードするには、次のようにツール 'jq'を使用できます。

# first, load the json text into a variable:
json='{"SALUTATION": "Hello world", "SOMETHING": "bla bla bla Mr. Freeman"}'

# then, prepare associative array, I use 'aa':
unset aa
declare -A aa

# use jq to produce text defining name:value pairs in the bash format
# using @sh to properly escape the values
aacontent=$(jq -r '. | to_entries | .[] | "[\"" + .key + "\"]=" + (.value | @sh)' <<< "$json")

# string containing whole definition of aa in bash
aadef="aa=($aacontent)"

# load the definition (because values may contain LF characters, aadef must be in double quotes)
eval "$aadef"

# now we can access the values like this: echo "${aa[SOMETHING]}"

警告: これはevalを使用しますが、json入力が不明なソースからのものである場合は危険です(evalが実行する可能性のある悪意のあるシェルコマンドが含まれている可能性があります)


Answer #2

この質問は回答されましたが、投稿された回答から要件を完全に満たすことができませんでした。 bash-newcomersに役立つちょっとした記事を以下に示します。

予知

基本的な連想配列宣言

#!/bin/bash

declare -A associativeArray=([key1]=val1 [key2]=val2)

declaration 、その keys 、および values 引用符( '" )で囲むこともでき values

#!/bin/bash

declare -A 'associativeArray=([key1]=val1 [key2]=val2)'

また、スペースまたは改行を介して各 [key]=value ペアを区切ることができます。

#!/bin/bash

declare -A associativeArray([key1]=value1
  ['key2']=value2 [key3]='value3'
  ['key4']='value2'               ["key5"]="value3"


  ["key6"]='value4'
  ['key7']="value5"
)

引用のバリエーションによっては、文字列をエスケープする必要がある場合があります。

インダイレクションを使用して、連想配列のキーと値の両方にアクセスする

function example {
  local -A associativeArray=([key1]=val1 [key2]=val2)

  # print associative array
  local key value
  for key in "${!associativeArray[@]}"; do
    value="${associativeArray["$key"]}"
    printf '%s = %s' "$key" "$value"
  done
}

サンプル関数の実行

$ example
key2 = val2
key1 = val1

前述の情報を知っていると、次のスニペットを導出できます。

次の例はすべて、上記の例の結果になります。

文字列評価

#!/usr/bin/env bash

function example {
  local arrayAsString='associativeArray=([key1]=val1 [key2]=val2)'
  local -A "$arrayAsString"

  # print associative array
}

JSONをJQにパイピングする

#!/usr/bin/env bash

function example {
  # Given the following JSON
  local json='{ "key1": "val1", "key2": "val2" }'

  # filter using `map` && `reduce`
  local filter='to_entries | map("[\(.key)]=\(.value)") |
    reduce .[] as $item ("associativeArray=("; . + ($item|@sh) + " ") + ")"'

  # Declare and assign separately to avoid masking return values.
  local arrayAsString;
  arrayAsString=$(cat "$json" | jq --raw-output "${filter}")
  local -A "$arrayAsString"

  # print associative array
}

jq -n / --null-inputオプション+ --argfile &&リダイレクト

#!/usr/bin/env bash

function example {
  # /path/to/file.json contains the same json as the first two examples
  local filter filename='/path/to/file.json'

  # including bash variable name in reduction
  filter='to_entries | map("[\(.key | @sh)]=\(.value | @sh) ")
    | "associativeArray=(" + add + ")"'

  # using --argfile && --null-input
  local -A "$(jq --raw-output --null-input --argfile file "$filename" \
    "\$filename | ${filter}")"

  # or for a more traceable declaration (using shellcheck or other) this
  # variation moves the variable name outside of the string

  # map definition && reduce replacement
  filter='[to_entries[]|"["+(.key|@sh)+"]="+(.value|@sh)]|"("+join(" ")+")"'

  # input redirection && --join-output
  local -A associativeArray=$(jq --join-output "${filter}" < "${filename}")

  # print associative array
}

以前の回答を確認する

@JánLalinský

JSONオブジェクトを(bashでループを使用せずに)bash連想配列に効率的にロードするには、次のようにツール 'jq'を使用できます。

# first, load the json text into a variable:
json='{"SALUTATION": "Hello world", "SOMETHING": "bla bla bla Mr. Freeman"}'

# then, prepare associative array, I use 'aa':
unset aa
declare -A aa

# use jq to produce text defining name:value pairs in the bash format
# using @sh to properly escape the values
aacontent=$(jq -r '. | to_entries | .[] | "[\"" + .key + "\"]=" + (.value | @sh)' <<< "$json")

# string containing whole definition of aa in bash
aadef="aa=($aacontent)"

# load the definition (because values may contain LF characters, aadef must be in double quotes)
eval "$aadef"

# now we can access the values like this: echo "${aa[SOMETHING]}"

警告: これはevalを使用しますが、json入力が不明なソースからのものである場合は危険です(evalが実行する可能性のある悪意のあるシェルコマンドが含まれている可能性があります)

これは次のように減らすことができます

function example {
  local json='{ "key1": "val1", "key2": "val2" }'
  local -A associativeArray=("$(jq -r '. | to_entries | .[] |
    "[\"" + .key + "\"]=" + (.value | @sh)' <<< "$json")")

  # print associative array
}

@fedorqui

キーと値が必要 で、JQ で jsonオブジェクトをkey = value形式に変換する方法に 基づいて、次のことができます:

$ jq -r "to_entries|map(\"\(.key)=\(.value|tostring)\")|.[]" file
SALUTATION=Hello world
SOMETHING=bla bla bla Mr. Freeman

より一般的な方法では、 while ... do; ... done < <(command) while jq を提供するだけで、値を配列 myarray[key] = value jq while ... do; ... done < <(command) while ... do; ... done < <(command) 構文:

declare -A myarray
while IFS="=" read -r key value
do
    myarray[$key]="$value"
done < <(jq -r "to_entries|map(\"\(.key)=\(.value)\")|.[]" file)

そして、次のような値をループできます。

for key in "${!myarray[@]}"
do
    echo "$key = ${myarray[$key]}"
done

この指定された入力に対して、次を返します。

SALUTATION = Hello world
SOMETHING = bla bla bla Mr. Freeman

このソリューションと私のソリューションの主な違いは、bashまたはjqで配列をループすることです。

各ソリューションは有効であり、ユースケースに応じて、一方が他方よりも役立つ場合があります。


Answer #3

キーと値が必要 で、JQ で jsonオブジェクトをkey = value形式に変換する方法に 基づいて、次のことができます:

$ jq -r "to_entries|map(\"\(.key)=\(.value|tostring)\")|.[]" file
SALUTATION=Hello world
SOMETHING=bla bla bla Mr. Freeman

より一般的な方法では、 while ... do; ... done < <(command) while jq を提供するだけで、値を配列 myarray[key] = value jq while ... do; ... done < <(command) while ... do; ... done < <(command) 構文:

declare -A myarray
while IFS="=" read -r key value
do
    myarray[$key]="$value"
done < <(jq -r 'to_entries|map("(.key)=(.value)")|.[]' file)

そして、次のような値をループできます。

for key in "${!myarray[@]}"
do
    echo "$key = ${myarray[$key]}"
done

この指定された入力に対して、次を返します。

SALUTATION = Hello world
SOMETHING = bla bla bla Mr. Freeman

Answer #4

コンテキスト:この回答は、もはや存在しない質問のタイトルに応答するように書かれています。

OPの質問は、実際にはオブジェクトと配列を説明しています。

ただし、 実際に JSON配列のヘルプを探している他の人々を支援するために、明示的にカバーする価値があります。

文字列に改行を含めることができない安全なケースの場合(およびbash 4.0以降が使用されている場合)、これは機能します。

str='["Hello world", "bla bla bla Mr. Freeman"]'
readarray -t array <<<"$(jq -r '.[]' <<<"$str")"

古いバージョンのbashと改行付きの文字列をサポートするには、 jq から読み取るためにNULで区切られたストリームを使用して、少し jq ます。

str='["Hello world", "bla bla bla Mr. Freeman", "this is\ntwo lines"]'
array=( )
while IFS= read -r -d '' line; do
  array+=( "$line" )
done < <(jq -j '.[] | (. + "\u0000")')




jq