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 ...)

答え2

parsetそのために作られた:

parset hd find {} -name \""*filter*"\" -type f ::: "${hdd_list[@]}"

ただし、一時ファイルを使用します。彼らはあなたのためにきれいになるので、あなたはそれらを処理する必要はありません。

もっと見る:https://www.gnu.org/software/parallel/parset.html

答え3

「&」の使用の全体的な意味を理解していないようです。

獣の本性バックグラウンドプロセスの場合できない親プロセスからバックグラウンドサブプロセスコンテンツにアクセスする...変数がグローバル変数として宣言されているかどうかに関係なく)。

経験している問題は、他の質問で説明されているものと同じです。郵便。デフォルトでは、一時ファイルは問題を回避する唯一の方法です。

答え4

特に並列化の場合は、find以下を確認してください。fdfindfindこれは基本的にマルチスレッドの拡張バージョンです。

それでも問題が解決しない場合は、以下をfdfind試してください。xargsこれにより、コマンドが並列に実行されます。次から借りるこの問題、次のように試すことができます(たとえ100%確信できないため、動作する前に修正する必要があるかもしれません)。

found="$( printf "%s\0" "${hdd_list[@]}" | xargs -0 -I {} find {} -name "*filter*" -type f )"

仕組み:

printf "%s\0" "${hdd_list[@]}":ヌル文字を区切り文字として使用してリストを印刷します。

| xargs -0 -I {} ...:nullで区切られた入力(-0)を使用してstdinを取得し、次のコマンドを呼び出します。すべてのインスタンスを見つけて{}入力フィールドに置き換えます。

関連情報