Bashで並列に変数を埋める

Bashで並列に変数を埋める

find複数のハードドライブ上のファイルにアクセスするコマンドを高速化するために、並列化を利用しようとしています。残念ながら、並列化は無視されたり、変数が埋められたりしません。

found=""; IFS=$'\n'

for hdd in "${hdd_list[@]}"
do
    found+=$'\n'$(find "$hdd" -name "*filter*" -type f &) # ignores parellelization
    found+=$'\n'$(find "$hdd" -name "*filter*" -type f) & # doesn't fill variable
done

一時ファイルを使用せずにこれは可能ですか?

ベストアンサー1

コマンド置換は、続行する前にコマンド内に開いたパイプからすべてのデータを取得するのを待ちます。スクリプトの実行中にシェルがバックグラウンドでデータを読み続けるのは、必要以上に複雑です。 (しかし、これは、コマンド置換のコマンドが最初に上位エントリを分岐して終了するなど、奇妙な操作を実行しても、パイプが最後に閉じられた場合(もしそうなら)、それでもすべての出力を得ることができることを意味します)ので、プロセスを配置します。バックグラウンドコマンドの置き換え($(... &)有用ではありません)。

完全な割り当てをバックグラウンド(foo=... &)に入れても機能しません。バックグラウンドジョブは別のプロセスで実行する必要があり、そのバックグラウンドプロセスはデフォルトのシェルプロセスメモリのシェル変数を変更できないためです。

すべてのプロセスを個別にパイプに接続し、並列に実行findおよび印刷するように構成できますが、パイプバッファが大きすぎて同時にすべてのプロセスから読み取る必要があることを意味します。シェルではこれを行うのは難しいですselect()。 (まあ、一部のシェルにはあるかもしれません。)

しかし、一時ファイルを使用する簡単なソリューションがあるため、すべてが複雑すぎます。

find完全な行(項目)だけを書き、順序を気にしないという点で実装が優れている場合は、すべての出力を単一のファイルにリダイレクトできます。

f=$(mktemp)
for hdd in "${hdd_list[@]}"; do
    find "$hdd" ... &
done >> "$f"
# read "$f"
rm -f "$f"

ただし、そうでない場合や確実に確認したい場合は、一時ディレクトリと各ディレクトリの出力ファイルを作成してくださいfind

d=$(mktemp -d)
i=1
for hdd in "${hdd_list[@]}"; do
    find "$hdd" > "$d/out$i.tmp" &
    i=$((i+1))
done
cat "$d"/*.tmp > "$d/all.out"
# read "$d/all.out"
rm -rf "$d"

もちろん、最初のファイルでは一時ファイルをスキップしてループから直接読み取ることができます。

find配列と一緒にシェルを使用しているので、出力も配列に保存したいかもしれません。たとえば、readarrayBash では各行を別の配列要素に配置します。

readarray -t files < <(find ...)

おすすめ記事