改善の余地はかなりあります。ここから始めましょう:
v1=($(cat $INPUT | jq '."config"[$i]."var1"[]'))
...まず、実際に使用する必要はありませんcat
; jq
入力ファイルから直接ではなく、パイプから読み取ることを強制するため、パフォーマンスが低下します。実行jq <"$INPUT"
するだけでより堅牢になります(または、より良いのは<"$input"
、シェルの組み込み関数と環境変数のために慣例で予約されているすべて大文字の名前の使用を避けるためです)。
次に、入力ファイル名の展開を含め、すべての変数展開を引用符で囲む必要があります。そうしないと、ファイル名にスペースが含まれるたびにバグが発生します。
3 番目に、IFS 内array=( $(stuff) )
のすべての文字の出力をstuff
分割し、その分割の結果を一連のグロブ式として展開します (したがって、出力に が含まれていて、テキスト ファイルを含むディレクトリでこのスクリプトを実行している場合は、結果配列内のそれらのファイルの名前)。改行のみで分割すると、複数単語の文字列を正しく解析できることを意味し、グロブ文字が存在する場合にこの手法を確実に使用するには、グロブ展開を無効にする必要があります。これを行う 1 つの方法は、このコマンドを実行する前に設定して実行することです。もう 1 つは、コマンドの出力をループにリダイレクトすることです (以下を参照)。*.txt
IFS=$'\n'
set -h
while read
第 4 に、コードへの文字列置換は、どの言語でも悪い習慣です。その方法は (ローカルで同等の) Bobby Tablesであり、実行可能コードとして処理されるコンテンツを提供するために、プロセスに渡されたデータのみを変更できるはずの誰かを許可します。 (ただし、この場合はjq
スクリプトとして、より完全な機能を備えた言語で任意のコードを実行するよりも危険性が低くなりますが、それでも、これにより余分なデータが出力に追加される可能性があります)。
次に、jq
改行で区切られたコンテンツを発行するようになったら、それを配列に読み込む必要はまったくありません。コンテンツをシェルから書き込んjq
だり、シェルに読み込んだりするときに、コンテンツを反復処理できるため、シェルが必要とするのを防ぐことができます。そのコンテンツをバッファリングするためにメモリを割り当てるには:
while IFS= read -r; do
echo "read content from jq: $REPLY"
done < <(jq -r --arg i "$i" '.config[$i | tonumber].var1[]' <"$input")
最後に、配列を操作したいとしましょう。これを行うには、落とし穴を回避する 2 つの方法があります。1 つは、IFS
明示的に設定し、割り当ての前にグロブ展開を無効にすることです。
IFS=$'\n' # split only on newlines
set -f
result=( $(jq -r ... <"$input") )
もう 1 つは、ループを使用して配列に割り当てることです。
result=( )
while IFS= read -r; do
result+=( "$REPLY" )
done < <(jq -r ... <"$input")
...または、@JohnKugelman で提案されているようread -a
に、1 回の操作で配列全体を読み取るために使用します。
IFS=$'\n' read -r -d '' -a result < <(jq -r ... <"$input")