Evg*_*nii 15 arrays bash json jq
我有一个Bash脚本.它以JSON获取数据.我需要将JSON数组转换为Bash数组.
例
{
"SALUTATION": "Hello world",
"SOMETHING": "bla bla bla Mr. Freeman"
}
Run Code Online (Sandbox Code Playgroud)
在Bash中我希望得到这样的值echo ${arr[SOMETHING]}
.
fed*_*qui 19
如果你想要键和值,并且基于如何在JQ中将json对象转换为key = value格式,你可以这样做:
$ jq -r "to_entries|map(\"\(.key)=\(.value|tostring)\")|.[]" file
SALUTATION=Hello world
SOMETHING=bla bla bla Mr. Freeman
Run Code Online (Sandbox Code Playgroud)
在更普遍的方式,你可以将值存储到一个数组myarray[key] = value
这个样子,只是通过提供jq
到while
与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)
Run Code Online (Sandbox Code Playgroud)
然后你可以循环遍历这样的值:
for key in "${!myarray[@]}"
do
echo "$key = ${myarray[$key]}"
done
Run Code Online (Sandbox Code Playgroud)
对于此给定输入,它返回:
SALUTATION = Hello world
SOMETHING = bla bla bla Mr. Freeman
Run Code Online (Sandbox Code Playgroud)
Sid*_*Sid 14
虽然这个问题得到了回答,但我无法从发布的答案中完全满足我的要求。这里有一篇小文章,可以帮助任何 bash 新手。
一个基本的关联数组声明
#!/bin/bash
declare -A associativeArray=([key1]=val1 [key2]=val2)
Run Code Online (Sandbox Code Playgroud)
您还可以在、 its和
周围使用引号 ( '
, "
) 。declaration
keys
values
#!/bin/bash
declare -A 'associativeArray=([key1]=val1 [key2]=val2)'
Run Code Online (Sandbox Code Playgroud)
您可以[key]=value
通过空格或换行符分隔每一对。
#!/bin/bash
declare -A associativeArray([key1]=value1
['key2']=value2 [key3]='value3'
['key4']='value2' ["key5"]="value3"
["key6"]='value4'
['key7']="value5"
)
Run Code Online (Sandbox Code Playgroud)
根据您的报价变体,您可能需要对字符串进行转义。
使用间接访问关联数组中的键和值
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
}
Run Code Online (Sandbox Code Playgroud)
运行示例函数
$ example
key2 = val2
key1 = val1
Run Code Online (Sandbox Code Playgroud)
了解上述花絮可以让您得出以下片段:
下面的例子都会有上面例子的结果
#!/usr/bin/env bash
example () {
local arrayAsString='associativeArray=([key1]=val1 [key2]=val2)'
local -A "$arrayAsString"
# print associative array
}
Run Code Online (Sandbox Code Playgroud)
#!/usr/bin/env bash
# Note: usage of single quotes instead of double quotes for the jq
# filter. The former is preferred to avoid issues with shell
# substitution of quoted strings.
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;
# Note: no encompassing quotation (")
arrayAsString=$(cat "$json" | jq --raw-output "${filter}")
local -A "$arrayAsString"
# print associative array
}
Run Code Online (Sandbox Code Playgroud)
#!/usr/bin/env bash
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
}
Run Code Online (Sandbox Code Playgroud)
@Ján Lalinský
要有效地将 JSON 对象加载到 bash 关联数组中(不使用 bash 中的循环),可以使用工具“jq”,如下所示。
Run Code Online (Sandbox Code Playgroud)# 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 可能执行的恶意 shell 命令),这很危险。
这可以简化为以下
example () {
local json='{ "key1": "val1", "key2": "val2" }'
local -A associativeArray=("$(jq -r '. | to_entries | .[] |
"[\"" + .key + "\"]=" + (.value | @sh)' <<< "$json")")
# print associative array
}
Run Code Online (Sandbox Code Playgroud)
@fedorqui
如果您想要键和值,并且基于如何将 json 对象转换为 JQ 中的键=值格式,您可以执行以下操作:
Run Code Online (Sandbox Code Playgroud)$ jq -r "to_entries|map(\"\(.key)=\(.value|tostring)\")|.[]" file SALUTATION=Hello world SOMETHING=bla bla bla Mr. Freeman
在更普遍的方式,你可以将值存储到一个数组
myarray[key] = value
这个样子,只是通过提供jq
到while
与while ... do; ... done < <(command)
语法:Run Code Online (Sandbox Code Playgroud)declare -A myarray while IFS="=" read -r key value do myarray[$key]="$value" done < <(jq -r "to_entries|map(\"\(.key)=\(.value)\")|.[]" file)
然后你可以循环遍历这样的值:
Run Code Online (Sandbox Code Playgroud)for key in "${!myarray[@]}" do echo "$key = ${myarray[$key]}" done
对于这个给定的输入,它返回:
Run Code Online (Sandbox Code Playgroud)SALUTATION = Hello world SOMETHING = bla bla bla Mr. Freeman
这个解决方案和我自己的解决方案之间的主要区别是在 bash 或 jq 中循环遍历数组。
每个解决方案都是有效的,并且根据您的用例,一个可能比另一个更有用。
上下文:这个答案是为了响应不再存在的问题标题而编写的..
OP的问题实际上描述了对象和数组.
可以肯定的是我们帮助其他人在未来谁是真正寻找一个JSON阵列的帮助下,虽然,这是值得覆盖他们明确.
对于安全的情况,字符串不能包含换行符(当使用bash 4.0或更新时),这有效:
str='["Hello world", "bla bla bla Mr. Freeman"]'
readarray -t array <<<"$(jq -r '.[]' <<<"$str")"
Run Code Online (Sandbox Code Playgroud)
为了支持旧版本的bash和带有换行符的字符串,我们使用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")')
Run Code Online (Sandbox Code Playgroud)