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