並列プロセスを使用して対話型bashループを高速化しますが、ループ内に連想配列を作成する必要があります。

並列プロセスを使用して対話型bashループを高速化しますが、ループ内に連想配列を作成する必要があります。

Bashでは、ファイルのリストを表すインデックス配列があります。

a=("1.json" "2.json" "3.json" ... "5309.json")

このJSONファイルの2つのデータフィールドを2つの連想配列に解析します。

declare -A idArr
declare -A valueArr

for i in "${a[@]}"; do
    jqId="$(jq -M ".fileId" <"${i}")"
    jqValue="$(jq -M ".value" <"${i}")"
    # If there are already items in the associative array, add the new items separated by a newline
    idArr[${i}]="${idArr[${i}]}${idArr[${i}]:+$'\n'}${jqId}"
    valueArr[${jqId}]="${valueArr[${jqId}]}${valueArr[${jqId}]:+$'\n'}${jqValue}"
done

一度に1つのファイルを繰り返すので、すべてのファイルを処理するのにかなり時間がかかります。ループ内で生成された連想配列は、ループが完了した後も引き続き範囲を超えなければならないという要件があります。

parallel複数の配列項目を同時に処理しながら、連想配列にデータを提供する方法(処理または他の方法を使用)はありますか?

ベストアンサー1

ここで遅いことができるのは、jqファイルごとに2つのsを実行し、プロセスをフォークしてjq その中で実行することが、おそらく小さなjsonファイルを処理するよりもはるかに多くの作業量です。

read0() { IFS= read -rd '' "$@"; }
add_line() {
  typeset -n _var="$1"
  _var+=${_var:+$'\n'}$2
}
shopt -s extglob failglob lastpipe
set -o pipefail

typeset -A idArr valueArr

jq -j '[input_filename, .fileId, .value] |
       map(gsub("\u0000"; "") + "\u0000") | add
      ' -- +([0123456789]).json |
  while read0 file && read0 id && read0 value; do
    add_line "idArr[$file]"    "$id"
    add_line "valueArr[$file]" "$var"
  done

一度だけ実行されますjqjqbashがループから並列に読み取るとき、NULで区切ってファイル名、ID、および値(存在する場合はNULを削除)を印刷します。

重要なヒント:するいいえわずかに偽装されているadd_lineため、コマンドインジェクションの脆弱性になる可能性があるため、任意のファイル名で呼び出してください。たとえば、代わりにを使用し、というファイルがある場合、再起動します!typeset -neval*.json+([0123456789]).json$(reboot).json

現在のバージョンのbashでは、二重引用符の代わりに一重引用符を使用してこの問題を解決できますが、idArr[$file]将来valueArr[$file]のバージョンのbashでは、namerefの逆参照に対してこれらの拡張を実行しないことを決定できるため、これは将来の証拠ではない可能性があります。

または、誤って設計された名前参照を削除し、evalそれらを明示的に使用してこれらの脆弱性を排除する可能性があります。

add_line() {
  eval "$1+=\${$1:+\$'\\n'}\$2"
}

そして必ず次のように呼び出してください。

    add_line 'idArr[$file]'    "$id"
    add_line 'valueArr[$file]' "$var"

その後、消毒を使用*.jsonしたり、必要としないことがあります。"${a[@]}"

「パラメータのリストが長すぎます。」エラーが発生した場合jq ... +([0123456789]).jsonにに置き換えてくださいprintf '%s\0' +([0123456789]).json | xargs -r0 jq ...

xargsGNU 'を使用して-Pそれらのいくつかを並列に実行することもできますが、コマンド出力のシリアル化は保証されておらず、個々のsの出力が互いに絡み合う可能性があるため、お勧めできjqません。 GNUはそうです。しかし、(おそらく)短いJSONファイルを解析するなどの単純な操作に比べてオーバーヘッドが多いため、追加の利点がない可能性があります。xargsjqparallel


1は標準入力jqとして扱われるので、-厳密に言うと、そのような名前のファイルが配列(または代わりに$aglob拡張子)に存在する場合はこれを。**.json./-

おすすめ記事