web-dev-qa-db-ja.com

複数のフォルダーでスクリプトを並行して実行する

高レベルディレクトリ内にいくつかのサブディレクトリがあります。各サブディレクトリには、いくつかのファイルとforループシェルスクリプトがあります。同じforループスクリプトが各サブディレクトリにあります。各サブディレクトリに移動して、forループスクリプトを複数の端末で並行して実行したいと思います。私はこれを試しましたが、逐次的に(逐次)行うようですが、すべてを並行して実行したいと思います。

find dir_* -type f -execdir sh for_loop.sh {} \;
6
user233520

おそらくこれに最適なツールは 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からの出力を使用することを可能にします。

4
dr_

これが正しいことを仮定すると-シリアルでのみ:

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つのジョブを実行することです。

Simple scheduling

代わりに、GNU Parallelは、プロセスが終了すると新しいプロセスを生成します-CPUをアクティブに保ち、時間を節約します。

GNU Parallel scheduling

インストール

セキュリティ上の理由から、パッケージマネージャと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

3
Ole Tange

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
_
3
ChristophS

パラレルモードで実行している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が使用されます。

2
user218374

あなたはあなたのトップレベルのディレクトリから行うことができます

for D in `find . -type d -maxdepth 1`
do 
     $D/<yourScriptName>.sh &
done

「&」はバックグラウンドで実行することです

0
M4rty