2017-02-13 15 views
4

一度に3つのジョブをバックグラウンドで実行するには、bashスクリプトが必要です。バックグラウンドで一定数のジョブを実行するbashスクリプト

私は、次の方法でこれを行うことができます知っている、と説明のために、私は仕事の数が6であると仮定します:

./j1 & 
./j2 & 
./j3 & 
wait 
./j4 & 
./j5 & 
./j6 & 
wait 

しかし、この方法で、例えば、J2は時間がかかった場合そのj1とj3を実行するには、長い時間実行されている1つのバックグラウンドジョブだけで立ち往生します。

1つのジョブが完了するたびに、bashはキュー内の次のジョブを開始して、任意の時点で3つのジョブの割合が維持されるようにする必要があります。おそらくループを使用して、この代替手段を実装するためのbashスクリプトを書くことは可能ですか?はるかに多くの仕事をする必要があることに注意してください。私はこの代替方法が私に多くの時間を節約することを期待しています。

これは私のスクリプトの草案です。私がbashでスクリプトを書いたことがないので、その正しさを検証し改善することを助けてくれることを願っています。このスクリプトでは、アイデア)を取り、herehere、およびhereから変更されています

for i in $(seq 6) 
do 
    # wait here if the number of jobs is 3 (or more) 
    while (((($(jobs -p | wc -l))) >= 3)) 
    do 
     sleep 5  # check again after 5 seconds 
    done 

    jobs -x ./j$i & 
done 
wait 

私見を、私はこのスクリプトは、必要な行動をすると思います。しかし、私が間違ってやっている場合や、このアイデアを実装するより良い方法がある場合、私はbashの専門家から知る必要があります。

ありがとうございました。 GNUのxargsので

+0

具体的には*のバージョンのbashですか? –

+4

このようなジョブを管理するには、 'parallel'のようなものを使うことをお勧めします。 – chepner

+0

ところで、 'seq'は一般的に悪い形式です。これはPOSIXで指定されておらず、bashにも組み込まれていないため、特定のシステム上に存在すると考える特別な理由はありません。代わりに[Cスタイルの 'for'ループ](http://wiki.bash-hackers.org/syntax/ccmd/c_for)を使用してください。 –

答えて

4

:bashの(4.xの)組み込みコマンドで

printf '%s\0' j{1..6} | xargs -0 -n1 -P3 sh -c './"$1"' _ 

max_jobs=3; cur_jobs=0 
for ((i=0; i<6; i++)); do 
    # If true, wait until the next background job finishes to continue. 
    ((cur_jobs >= max_jobs)) && wait -n 
    # Increment the current number of jobs running. 
    ./j"$i" & ((++cur_jobs)) 
done 
wait 

注組み込みコマンドに依存するアプローチはいくつかのコーナーケースを持っている - あなたが持っている場合1つのwait -nが複数のジョブを収穫できるため、複数のスロットを効果的に消費します。

max_jobs=3 
declare -A cur_jobs=() # build an associative array w/ PIDs of jobs we started 
for ((i=0; i<6; i++)); do 
    if ((${#cur_jobs[@]} >= max_jobs)); then 
    wait -n # wait for at least one job to exit 
    # ...and then remove any jobs that aren't running from the table 
    for pid in "${!cur_jobs[@]}"; do 
     kill -0 "$pid" 2>/dev/null && unset cur_jobs[$pid] 
    done 
    fi 
    ./j"$i" & cur_jobs[$!]=1 
done 
wait 

...明らかに多くの作業で、まだマイナーなレースを持っている:私たちはより堅牢になりたかったならば、私たちは以下のようなもので終わるかもしれません。代わりにxargs -Pを使用することを検討してください。 :)

+0

あなたの最初の 'bash'ループは' curr_jobs'を減少させることはありません。 – chepner

+0

@chepner、デクリメントする必要はありません。私たちは、3つを始めた後は、開始するたびに1つずつ刈り取ることができるようにしています。 'wait -n'が実際に複数のジョブを刈り取っているケースを気にするなら、それは2番目のバージョンのためです。 –

0

多分これが助けることができ..

サンプルをユースケース:実行 'スリープ20' 30回、単なる一例として。それはどんな仕事でも別のスクリプトでもあります。私たちのコントロールロジックは、「すでに何人が解雇されたのか」をチェックし続けることです。 whileループ内で、 "max processes defined"以下です。もしそうでなければ、1を発射し、もしそうなら0.5秒寝る。

スクリプト出力:以下のスナップでは、max = 30を設定したので、30 'sleep 20'コマンドがバックグラウンドで実行されていることがわかります。

%[email protected]> ps -ef|grep 'sleep 20'|grep -v grep|wc -l 
30 
%[email protected]> 

実行時のジョブ数: "max.txt"(max=$(cat max.txt))ファイルから値をとり、whileループの各反復で適用する、パラメータ "max"を持つスクリプト。以下に示すように、これを45に変更し、バックグラウンドで45 'スリープ20'コマンドを実行しました。メインスクリプトをバックグラウンドに置き、制御するために "max.txt"の中の最大値を変更し続けることができます。

%[email protected]> cat > max.txt 
45 
^C 
%[email protected]> ps -ef|grep 'sleep 20'|grep -v grep|wc -l 
45 
%[email protected]> 

スクリプト:

#!/bin/bash 
#---------------------------------------------------------------------# 
proc='sleep 20' # Your process or script or anything.. 
max=$(cat max.txt) # configure how many jobs do you want 
curr=0 
#---------------------------------------------------------------------# 
while true 
do 
    curr=$(ps -ef|grep "$proc"|grep -v grep|wc -l); max=$(cat max.txt) 
    while [[ $curr -lt $max ]] 
     do 
    ${proc} &  # Sending process to background. 
    max=$(cat max.txt) # After sending one job, again calculate max and curr 
    curr=$(ps -ef|grep "$proc"|grep -v grep|wc -l) 
    done 
    sleep .5 # sleep .5 seconds if reached max jobs. 
done 
#---------------------------------------------------------------------# 

それはどんな有用であったならば、私たちは知ってみましょう。

+0

'$ {proc}&'には、[BashFAQ#50](http://mywiki.wooledge.org/BashFAQ/050)に記載されているすべてのバグがあります。 –

+0

...ここには他にもいくつかの問題があります。多くのプロセスではサブシェルが生成されます.2つのサブシェルを実行するスクリプトを生成すると、直接生成されたすべてのコピーはあなたの 'wc -l'で3つとカウントされます。 'ps'アプローチは、この仕事の直接の子供たちだけでなく、システム全体のすべてのプロセスを数えます。すべてのジョブが正規表現として一致するわけではありません - もし 'find '/incoming/[a-zA-Z]*.d' -mindepth 1 -maxdepth 1 -exec my-process'を実行すると、' [a-zA grepの-Z] 'はps出力の関連する位置の' ['文字と一致しません。 –

+0

チャールズさんに感謝します。私はあなたが言ったことをチェックし、うまくいけば新しいことを学ぶつもりです。乾杯! – User9102d82

2

使用GNUパラレル:

parallel -j3 ::: ./j{1..6} 

またはあなたのシェルが..展開を行っていない場合(例えばCSH):あなたはGNUパラレルをインストールすることはできませんと思うなら

seq 6 | parallel -j3 ./j'{}' 

http://oletange.blogspot.dk/2013/04/why-not-install-gnu-parallel.htmlを読んでください。それをインストールできない理由についてコメントを残してください。

関連する問題