高レベルディレクトリ内にいくつかのサブディレクトリがあります。各サブディレクトリには、いくつかのファイルとforループシェルスクリプトがあります。同じforループスクリプトが各サブディレクトリにあります。各サブディレクトリに移動して、forループスクリプトを複数の端末で並行して実行したいと思います。私はこれを試しましたが、逐次的に(逐次)行うようですが、すべてを並行して実行したいと思います。
find dir_* -type f -execdir sh for_loop.sh {} \;
おそらくこれに最適なツールは GNU Parallel です。
parallel ::: dir_*/for_loop.sh
GNU Parallelは各ジョブを並行して実行するだけでなく、出力を逆多重化するため、相互に干渉しません。
そのmanページから:
GNUパラレルは、1つ以上のコンピューターを使用してジョブを並列に実行するためのシェルツールです。ジョブは、単一のコマンドまたは小さなスクリプトで、入力の各行に対して実行する必要があります。典型的な入力は、ファイルのリスト、ホストのリスト、ユーザーのリスト、URLのリスト、またはテーブルのリストです。ジョブは、パイプから読み取るコマンドにすることもできます。 GNU parallelは、入力をブロックに分割し、ブロックを各コマンドに並列でパイプ処理します。
今日xargsとteeを使用している場合、GNU parallelはGNU parallelはxargsと同じオプションを持つように記述されています。シェルのループでは、GNU parallelがほとんどのループを置き換えることができ、複数のジョブを並行して実行することにより、より高速に実行できる可能性があります。
GNU Parallelは、コマンドからの出力が、コマンドを順次実行した場合に得られる出力と同じであることを確認します。これは他のプログラムの入力としてGNU parallelからの出力を使用することを可能にします。
これが正しいことを仮定すると-シリアルでのみ:
find dir_* -type f -execdir sh for_loop.sh {} \;
次に、それを次のものに置き換えることができるはずです:
find dir_* -type f | parallel 'cd {//} && sh for_loop.sh {}'
複数の端末で実行するにはGNU Parallelは、独自のtmux
ペインで各コマンドを実行するtmux
をサポートします。
find dir_* -type f | parallel --tmuxpane 'cd {//} && sh for_loop.sh {}'
デフォルトでは、CPUコアごとに1つのジョブになります。あなたのケースでは、コアよりも1つ多いジョブを実行したいかもしれません:
find dir_* -type f | parallel -j+1 --tmuxpane 'cd {//} && sh for_loop.sh {}'
GNU Parallelは一般的なパラレライザーであり、同じマシン上で、またはsshにアクセスできる複数のマシン上で、ジョブを簡単に並列実行できます。
4つのCPUで実行する32の異なるジョブがある場合、並列化する簡単な方法は、各CPUで8つのジョブを実行することです。
代わりに、GNU Parallelは、プロセスが終了すると新しいプロセスを生成します-CPUをアクティブに保ち、時間を節約します。
インストール
セキュリティ上の理由から、パッケージマネージャとGNU Parallelをインストールする必要がありますが、GNU Parallelがディストリビューションにパッケージ化されていない場合は、個人用インストールを実行できます。 rootアクセスは必要ありません。これを行うと、10秒で実行できます。
(wget -O - pi.dk/3 || curl pi.dk/3/ || fetch -o - http://pi.dk/3) | bash
他のインストールオプションについては http://git.savannah.gnu.org/cgit/parallel.git/tree/README を参照してください
詳細
その他の例を見る: http://www.gnu.org/software/parallel/man.html
紹介ビデオを見る: https://www.youtube.com/playlist?list=PL284C9FF2488BC6D1
チュートリアルをご覧ください: http://www.gnu.org/software/parallel/parallel_tutorial.html
サポートを受けるには、メーリングリストにサインアップしてください: https://lists.gnu.org/mailman/listinfo/parallel
find
はあなたのためにそれをしません。
次のように、skriptを作成し、for_loop.shスクリプトを見つけて実行します。
_#!/bin/bash
for theScript in $(find dir_* -name for_loop.sh); do
"$theScript" &
done
_
スクリプトをサブディレクトリ内で実行する必要がある場合は、前にcd
を試してください。おそらくcd $(dirname "$theScript") && . $(basename "$theScript")
のようになります。
私の例は詳細にテストされておらず、エラー耐性もありません...
編集1:
Sato Katsura が正しくコメントしたため、ディレクトリ名にスペースが含まれている場合、上記のスクリプトは機能しなくなります。
したがって、ループをread
に変更しました。
_#!/bin/bash
find dir_* -name for_loop.sh | while IFS= read -r theScript; do
"$theScript" &
done
_
パラレルモードで実行しているfind
の出力をxargs
に渡す必要があります。
find dir_*/ -type f -name for_loop.sh -print0 | xargs -0 -r -n 1 -P 3 -t sh
ここでfind
に、dir_という名前で始まるディレクトリの下でfor_loop.shという名前のすべてのファイルを再帰的に検索し、それらを一度に1つのファイルであるxargsに並列モードで実行するように依頼しています。常に3つのプロセス。
find
によるファイル名の印刷と、xargs
によるnullでの分割では、null区切り文字\0
が使用されます。
あなたはあなたのトップレベルのディレクトリから行うことができます
for D in `find . -type d -maxdepth 1`
do
$D/<yourScriptName>.sh &
done
「&」はバックグラウンドで実行することです