我使用jq
来parsingJSON文件,将每个JSON数组抽取到一个shell数组中。
我目前的代码如下所示:
for ((i = 0; i < ${#nvars[@]}; i++)); do v1=($(cat $INPUT | jq '."config"[i]."var1"[]')) echo $v1 done
错误信息:
error: i is not defined
我也换了
v1=($(cat $INPUT | jq '."config"[i]."var1"[]'))
同
v1=($(cat $INPUT | jq '."config"[$i]."var1"[]'))
还是行不通。 任何想法? 任何帮助表示赞赏!
编辑:示例input数据
{ "config-vars":[ { "var1":["v1","v2"], "var2":"" }, { "var1":["v3",""], "var2":"v4" } ] }
有一些相当大的改进空间。 我们从这里开始:
v1=($(cat $INPUT | jq '."config"[$i]."var1"[]'))
…首先,你实际上并不需要使用cat
; 它会降低性能,因为它强制jq
从管道而不是从输入文件直接读取。 只要运行jq <"$INPUT"
就会更健壮(或者更好的是,为了避免使用全部大写的名字,而这些名字被shell惯例和环境变量保留)。
其次,你需要引用所有的变量扩展,包括扩展输入文件的名字 – 否则,只要你的文件名包含空格就会得到错误。
第三, array=( $(stuff) )
将IFS中所有字符的stuff
的输出进行分割,并将分割的结果展开为一系列glob表达式(所以如果输出包含*.txt
,脚本在包含文本文件的目录中,您将获得结果数组中的这些文件的名称)。 只拆分换行符意味着您可以正确解析多个字符串,并且必须禁用glob扩展,才能在存在glob字符的情况下可靠地使用此技术。 一种方法是设置IFS=$'\n'
并在运行此命令之前运行set -h
; 另一个是将你的命令的输出重定向到一个while read
循环(如下所示)。
第四,字符串替换成代码在任何语言中都是不好的做法 – 这种方式(本地等价于) Bobby表允许某人应该只能改变传入进程的数据,以提供被处理为可执行代码的内容(虽然在这种情况下,作为一个jq
脚本,这是比在一个更全面的功能语言的任意代码执行危险性更低;但是,这可以允许额外的数据添加到输出)。
接下来,一旦让jq
发出以换行符分隔的内容,根本不需要将其读入数组中:您可以迭代jq
写入的内容并读入到shell中,从而防止shell从需要分配内存到缓冲区的内容:
while IFS= read -r; do echo "read content from jq: $REPLY" done < <(jq -r --arg i "$i" '.config[$i | tonumber].var1[]' <"$input")
最后 – 假设你想要使用一个数组。 有两种方法可以避免陷阱。 一个是显式设置IFS
并在赋值之前禁用glob扩展:
IFS=$'\n' # split only on newlines set -f result=( $(jq -r ... <"$input") )
另一个是分配给你的数组与循环:
result=( ) while IFS= read -r; do result+=( "$REPLY" ) done < <(jq -r ... <"$input")
…或者像@JohnKugelman所建议的那样,使用read -a
在一个操作中读取整个数组:
IFS=$'\n' read -r -d '' -a result < <(jq -r ... <"$input")
变量不会插入在单引号内。 使用双引号,并删除现有的引号。
v1=($(cat $INPUT | jq ".config[$i].var1[]"))
或者使用--arg
选项,然后可以使用单引号。
v1=($(cat $INPUT | jq --arg i "$i" '.config[$i].var1[]'))
你也可以修复猫的无用用法:
v1=($(jq ".config[$i].var1[]" "$INPUT"))
此外,请参阅@ CharlesDuffy的答案,为什么像这样分配数组是不安全的。
jq
能够一次性提取结构,所以整个循环是多余的。 如果输入的JSON包含的记录数多于nvars
值,则使用索引进行nvars
。
jq -r '."config-vars"[]."var1"' "$INPUT" | head -n "${#nvars[@]}" # If you need just the #nvars first values
如果您已经将一些JSON的结果存储到名为$ MY_VAR的变量中:
while IFS= read -r; do echo “$REPLY” done < <(echo $MY_VAR | jq -r '.[]')
我花了太多时间才弄明白这一点。 我所看到的所有例子都是令人费解的,我必须把它们拼凑在一起。