メインスクリプトから添え字を実行しようとしていますが、n以下で実行されることを確認したい同時に。
次の簡略化した例を示します。
各添え字は、RAM(/dev/shm/
)に一意のタイムスタンプで作成された名前のダミーファイルを作成し、完了したら削除します。
メインスクリプトは、添え字に由来する/dev/shm/
内のダミーファイルの数をカウントし、2つ以上のダミーファイルがすでに実行されている場合、新しい添え字を起動しません(起動すべきではありません)。
ただし、メインスクリプトはwhile条件を無視しているようで、5つの添え字すべてを一度に起動します。
私のコードの何が問題になっていますか?
mainscript.txt
#!/bin/bash
for counter in $(seq 1 5)
do
while [ $(ls -1 /dev/shm/|grep "script044"|wc -l) -ge 2 ]
do
sleep 0
done
xterm -e "bash script044.txt" &
done
exit
script044.txt(添え字)
#!/bin/bash
tempfilename="script044_"$(date +%Y%m%d%H%M%S)_${RANDOM}
echo > /dev/shm/${tempfilename}
for counter in $(seq 1 $(shuf -i 10-45 -n 1))
do
sleep 1
printf "${counter}\r"
done
rm /dev/shm/${tempfilename}
exit
(コンベンション-.txt
は単なるプレーンテキストファイルです。 .sh
ファイルはシェルスクリプトファイルです。).
Mainscript.txtスクリプトに競合状態があります。具体的には、whileループは、script044.txtスクリプトが一時ファイルを作成できるようになる前に次の反復を開始します。実際、これらのファイルが作成される前に、ループ全体が繰り返されます。
この種のことを処理するためのより堅牢な方法は、一時ファイルを忘れて、代わりにシェル組み込みのwait
を使用することです。
#!/bin/bash
pid_count=0
for counter in $(seq 1 5)
do
xterm -e "bash script044.txt" &
if (( ++pid_count > 2 )); then
wait -n
((pid_count--))
fi
done
これにより、サブプロセスが開始されるたびにカウンターがインクリメントされます。カウンターが3より大きい場合、次のサブプロセスを終了するためにwait
します。 wait
が戻ったら、カウンターをデクリメントし、もう一度回って次のxtermを開始します。
Script044.txtからすべてのtempfilename
関連の行を削除できます-それらは不要になりました。
@chepnerが指摘しているように、必要な-n
オプションはbash4.3以降でのみ使用できます。
シェルのみのソリューションを目指している場合は役に立ちませんが、GNU parallelは、この正確な解決に役立つ sem
コマンドを提供します状況。
次の(スクリプトがないため、テストされていません)は、ジョブを5回実行する必要がありますが、一度に2回だけ実行し、最後に終了するのを待ちます。
LIMIT=2
for i in {1..5}; do
sem -j $LIMIT 'term -e "bash script044.txt"'
done
sem --wait
IPCが必要なようです。スリープをループして毎回テストを実行するのではなく、子プロセスがいつ完了したかを通知するのを待つことができます。これがパイプの目的です。
子プロセスを親に報告させることができます。パイプを開いて、彼らと共有します。彼らが終わったとき、彼らはただ親に知らせる必要があります。
_sub()( trap "echo >&9" 0
sleep 5
)
eval "exec 9<>"<(echo);i=0
until [ "$((i+=1))" -gt 5 ]
do sub & read na <&9
date +%S:%t"$i"
done
_
プロセス置換を使用して開きます。シェルでこれを実行できない場合は、代わりに次を使用できます。
_mkfifo pipe; exec 9<>pipe; rm pipe; echo >&9
_
これで、最初のecho
がパイプに1行を配置します-どちらの場合も。これにより、最初から1つの待機プロセスが先行します。つまり、2つの並行プロセスをすべて実行します。このスクリプトは、date
を使用して、各sub()
呼び出し間の秒数をレポートします。出力は次のとおりです。
_34: 1
39: 2
39: 3
44: 4
44: 5
_
そこ。ご覧のとおり、5秒ごとに子が死亡し、その場合、echo
はread
が現在ブロックしているパイプへの行です。 read
findが入力の改行になるとすぐに、実行中の処理を終了して最初からやり直すことができます。
Script_044にtrap
を入れる必要があります。これは、子プロセスが終了したときに父親に呼び出すように指示します。
これを実現する一般的な方法は、xargsを使用することです。
printf "%s\n" {1..5} | xargs -P2 -n1 -i xterm -e '/bin/echo Job {}; bash'
printfは、xargsに値を入力するためだけにあります。 -iフラグが使用されている場合、xargsのデフォルトのreplace-strは{}です。詳細については、xargsのマンページをお読みください。これは、GNUツールとシェルとしてのbashで機能するはずです。
xargs flags:
-P Run up to max-procs processes at a time.[…]
-n Use at most max-args arguments per command line.[…]
-i/-I Replace occurrences of replace-str in the initial-arguments with names read from standard input.[…]
xterm
..の新しいインスタンスを起動した直後に遅延を挿入します。
xterm -e "bash script044.txt" &
sleep 0.1
GNU Parallelを使用すると、次のようになります。
seq 1 5 | parallel -j2 -N0 'xterm -e "bash script044.txt"'
GNU Parallelは一般的な並列処理機能であり、同じマシン上またはsshアクセスできる複数のマシン上でジョブを簡単に並列実行できます。多くの場合、for
ループを置き換えることができます。
4つのCPUで実行する32の異なるジョブがある場合、並列化する簡単な方法は、各CPUで8つのジョブを実行することです。
代わりに、GNU Parallelは、終了時に新しいプロセスを生成します。つまり、CPUをアクティブに保ち、時間を節約します。
インストール
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