我有一个像这样的 JSON 数组:
{
"SITE_DATA": {
"URL": "example.com",
"AUTHOR": "John Doe",
"CREATED": "10/22/2017"
}
}
Run Code Online (Sandbox Code Playgroud)
我希望使用 jq 迭代这个数组,这样我就可以将每个项目的键设置为变量名,将值设置为它的值。
例子:
到目前为止,我对数组进行了迭代,但创建了一个字符串:
constants=$(cat ${1} | jq '.SITE_DATA' | jq -r "to_entries|map(\"\(.key)=\(.value|tostring)\")|.[]")
Run Code Online (Sandbox Code Playgroud)
哪些输出:
URL=example.com
AUTHOR=John Doe
CREATED=10/22/2017
Run Code Online (Sandbox Code Playgroud)
我希望在脚本中进一步使用这些变量:
echo ${URL}
Run Code Online (Sandbox Code Playgroud)
但这目前与空输出相呼应。我猜我需要一个eval或什么在那里,但似乎无法将我的手指放在上面。
Mic*_*mer 36
您的原始版本将eval无法运行,因为作者姓名中包含空格 - 它会被解释为运行Doe环境变量AUTHOR设置为John. 也几乎从不需要管道jq到自身 -内部管道和数据流可以将不同的过滤器连接在一起。
所有这些只有在您完全信任输入数据(例如,它是由您控制的工具生成)时才有意义。下面详细介绍了几个可能的问题,但让我们假设数据本身肯定是您目前期望的格式。
您可以制作一个更简单的 jq 程序版本:
jq -r '.SITE_DATA | to_entries | .[] | .key + "=" + (.value | @sh)'
Run Code Online (Sandbox Code Playgroud)
输出:
URL='example.com'
AUTHOR='John Doe'
CREATED='10/22/2017'
Run Code Online (Sandbox Code Playgroud)
不需要map:.[]处理通过管道的其余部分将数组中的每个对象作为单独的 item 处理,因此最后一个之后的所有内容都|分别应用于每个对象。最后,我们只是用普通的+连接组合一个有效的 shell 赋值字符串,包括适当的引号和用@sh.
这里所有的管道都很重要——没有它们,你会得到相当无用的错误消息,其中程序的各个部分在微妙的不同上下文中进行评估。
如果您完全信任输入数据并具有您想要的效果,则此字符串是eval可以的:
eval "$(jq -r '.SITE_DATA | to_entries | .[] | .key + "=" + (.value | @sh)' < data.json)"
echo "$AUTHOR"
Run Code Online (Sandbox Code Playgroud)
与以往一样,在使用 时eval,请小心信任您获得的数据,因为如果它是恶意的或只是采用意外格式,事情可能会出错。特别是,如果密钥包含 shell 元字符(如$或 空格),这可能会创建一个正在运行的命令。例如,它还可能会PATH意外覆盖环境变量。
如果您不信任数据,要么根本不执行此操作,要么过滤对象以仅包含您首先需要的键:
jq '.SITE_DATA | { AUTHOR, URL, CREATED } | ...'
Run Code Online (Sandbox Code Playgroud)
如果值是一个数组,您也可能会遇到问题,所以.value | tostring | @sh会更好 - 但这个警告列表可能是一个很好的理由,首先不要这样做。
也可以建立一个关联数组,而不是同时引用键和值:
eval "declare -A data=($(jq -r '.SITE_DATA | to_entries | .[] | @sh "[\(.key)]=\(.value)"' < test.json))"
Run Code Online (Sandbox Code Playgroud)
在此之后,${data[CREATED]}包含创建日期等,无论键或值的内容是什么。这是最安全的选项,但不会导致可以导出的顶级变量。当一个值是一个数组时,它仍然可能会产生 Bash 语法错误,如果它是一个对象,它可能仍然会产生一个 jq 错误,但不会执行代码或覆盖任何东西。
cas*_*cas 17
基于@Michael Homer 的回答,您可以eval通过将数据读入关联数组来完全避免潜在的不安全。
例如,如果您的 JSON 数据位于名为 的文件中file.json:
#!/bin/bash
typeset -A myarray
while IFS== read -r key value; do
myarray["$key"]="$value"
done < <(jq -r '.SITE_DATA | to_entries | .[] | .key + "=" + .value ' file.json)
# show the array definition
typeset -p myarray
# make use of the array variables
echo "URL = '${myarray[URL]}'"
echo "CREATED = '${myarray[CREATED]}'"
echo "AUTHOR = '${myarray[URL]}'"
Run Code Online (Sandbox Code Playgroud)
输出:
$ ./read-into-array.sh
declare -A myarray=([CREATED]="10/22/2017" [AUTHOR]="John Doe" [URL]="example.com" )
URL = 'example.com'
CREATED = '10/22/2017'
AUTHOR = 'example.com'
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
46362 次 |
| 最近记录: |