还有相当大的改进空间。让我们从这里开始:
v1=($(cat $INPUT | jq '."config"[$i]."var1"[]'))
...首先,您实际上不需要使用cat
;它会降低你的表现,因为它迫使jq
从管道读取而不是直接从输入文件读取。刚跑jq <"$INPUT"
会更稳健(或者更好,<"$input"
,以避免使用全大写名称,这些名称按照惯例为 shell 内置函数和环境变量保留)。
其次,您需要引用所有变量扩展,包括输入文件名的扩展 - 否则,只要文件名包含空格,您就会遇到错误。
Third, array=( $(stuff) )
分割输出stuff
on IFS 中的所有字符,并将该拆分的结果扩展为一系列 glob 表达式(因此,如果输出包含*.txt
,并且您在包含文本文件的目录中运行此脚本,您将在结果数组中获取这些文件的名称)。仅按换行符拆分意味着您可以正确解析多单词字符串,并且在存在 glob 字符的情况下可靠地使用此技术之前,必须禁用 glob 扩展。一种方法是设置IFS=$'\n'
并运行set -h
在运行此命令之前;另一个是将命令的输出重定向到while read
循环(如下所示)。
第四,在任何语言中,将字符串替换为代码都是不好的做法——这种方式就是(本地等价物)鲍比桌 http://xkcd.com/327/,允许那些应该只能更改传递到您的进程的数据的人提供作为可执行代码处理的内容(尽管在这种情况下,作为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")
最后——假设你do想要使用数组。有两种方法可以避免陷阱。一是设置IFS
显式地并在赋值之前禁用全局扩展:
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")