n個以下の並列サブシェルを実行する方法

n個以下の並列サブシェルを実行する方法

メインスクリプトでサブスクリプトを実行しようとしていますが、超えないようにしたいと思います。N添字は同時に実行されます。

次の簡単な例はこれを示しています。

/dev/shm/各添字は、独自のタイムスタンプで構成された名前を使用してRAM()に仮想ファイルを作成し、完了すると削除します。

デフォルトのスクリプトは、添え字で発生したダミーファイルの数を計算し、/dev/shm/2つ以上の添え字がすでに実行されている場合は、新しい添え字を開始しません(開始しないでください)。

しかし、デフォルトのスクリプトはwhile条件を無視し、5つの添え字をすべてすぐに開始するようです。

私のコードに問題がありますか?

メインスクリプト.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

答え1

(慣例 -プレーン.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オプションはbash 4.3以降でのみ利用可能です。

答え2

目標がシェル専用のソリューションであれば役に立ちませんが、GNU Parallelは次のいずれかを提供します。semコマンドを使用すると、この状況を解決するのに役立ちます。

次の(あなたのスクリプトがないのでテストされていません)は、タスクを5回実行する必要がありますが、一度に2回だけ最終終了を待って実行する必要があります。

LIMIT=2
for i in {1..5}; do
    sem -j $LIMIT 'term -e "bash script044.txt"'
done
sem --wait

答え3

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つの待機プロセスよりも先になります。つまり、常に2つの同時プロセスが実行されることを意味します。このスクリプトはdate各呼び出し間の秒数を報告しますsub()。出力は次のとおりです。

34: 1
39: 2
39: 3
44: 4
44: 5

そこに。ご覧のように、5秒ごとに子プロセスが終了し、終了すると現在ブロックされているパイプへのechoラインになります。 findは、入力で改行文字に遭遇するとすぐに実行中の操作を終了して再開できますreadread

trap完了したら、子プロセスに親プロセスを呼び出すように指示するコマンドをscript_044に追加するだけです。

答え4

新しいインスタンスを起動した後、少し遅延を挿入しますxterm...

        xterm -e "bash script044.txt" &
        sleep 0.1

関連情報