54

別の質問に対するこの回答では、次のように言われました。

スクリプトでは、ジョブ制御がありません (そして、それを有効にしようとするのはばかげています)

これを聞いたのはこれが初めてで、ジョブ制御の bash.info セクション (第 7 章) を調べたところ、これらのアサーションのいずれについても言及されていませんでした。[更新: man ページは少し良くなり、「典型的な」使用方法、デフォルト設定、および端末 I/O について言及されていますが、スクリプトに対してジョブ制御が特に不適切である理由については言及されていません。]

では、なぜスクリプトベースのジョブ制御が機能しないのでしょうか? また、何が悪い習慣 (別名「ばか」) になるのでしょうか?

編集:問題のスクリプトは、バックグラウンド プロセスを開始し、2 番目のバックグラウンド プロセスを開始してから、最初のプロセスをフォアグラウンドに戻そうとします。これにより、(直接実行されているかのように) 通常のターミナル I/O が得られ、その後、リダイレクトすることができます。スクリプトの外側。バックグラウンドプロセスに対してそれを行うことはできません。

他の質問に対する受け入れられた回答で指摘されているように、ジョブ制御を試行せずにその特定の問題を解決する他のスクリプトが存在します。罰金。そして、お粗末なスクリプトは、ハードコードされたジョブ番号を使用しています — 明らかにまずいです。しかし、ジョブ コントロールが根本的に運命づけられたアプローチであるかどうかを理解しようとしています。まだまだ活躍できそうです…。

4

7 に答える 7

36

bgとを使用したジョブ制御はfg、対話型シェルでのみ役立ちます。ただし&、 と組み合わせて使用​​すると、waitスクリプトでも役立ちます。

マルチプロセッサ システムでは、バックグラウンド ジョブを生成すると、スクリプトのパフォーマンスが大幅に向上します。たとえば、CPU ごとに少なくとも 1 つのコンパイラを起動するビルド スクリプトや、ImageMagick ツールを使用して画像を並列処理する場合などです。

次の例では、最大 8 つの並列 gcc を実行して、配列内のすべてのソース ファイルをコンパイルします。

#!bash
...
for ((i = 0, end=${#sourcefiles[@]}; i < end;)); do
    for ((cpu_num = 0; cpu_num < 8; cpu_num++, i++)); do
        if ((i < end)); then gcc ${sourcefiles[$i]} & fi
    done
    wait
done

これについて「愚か」なことは何もありません。waitただし、スクリプトが続行する前にすべてのバックグラウンド ジョブを待機するコマンドが必要になります。$!最後のバックグラウンド ジョブの PID は変数に格納されるため、 wait ${!}. コマンドにも注意してくださいnice

このようなコードは、makefile で役立つ場合があります。

buildall:
    for cpp_file in *.cpp; do gcc -c $$cpp_file & done; wait

これにより、 よりもはるかに細かい制御が可能になりmake -jます。

(write not )&のような行末記号であることに注意してください。;command&command&;

お役に立てれば。

于 2012-10-02T08:54:06.577 に答える
8

ジョブ制御は、対話型シェルを実行している場合、つまり stdin と stdout が端末デバイス (Linux では /dev/pts/*) に接続されていることがわかっている場合にのみ役立ちます。次に、フォアグラウンドに何かを置き、バックグラウンドに別のものを置きます。

一方、スクリプトにはそのような保証はありません。スクリプトは実行可能にすることができ、ターミナルを接続せずに実行できます。この場合、フォアグラウンド プロセスまたはバックグラウンド プロセスを使用しても意味がありません。

$!ただし、他のコマンドをバックグラウンドで非対話的に実行し (コマンド ラインに「&」を追加) 、. 次に、killそれらを強制終了または一時停止するために使用します(シェルがインタラクティブな場合、端末で Ctrl-C または Ctrl-Z をシミュレートします)。wait( の代わりにfg) を使用して、バックグラウンド プロセスが終了するのを待つこともできます。

于 2009-03-27T15:55:05.337 に答える
0

おそらくo/tですが、長時間実行されるジョブでサーバーにsshするときにnohupを頻繁に使用するため、ログアウトしてもジョブは完了します。

マスターインタラクティブシェルからの停止と開始、およびバックグラウンドプロセスの生成を混同しているのではないでしょうか? wait コマンドを使用すると、多くのものを生成してから、それらがすべて完了するのを待つことができます。前述のように、私は常に nohup を使用しています。これはこれよりも複雑で、あまり使用されていません。sh もこのモードをサポートしています。マニュアルをご覧ください。

あなたも持っています

kill -STOP pid

次のように、現在実行中の sudo を一時停止したい場合、私はよくこれを行います。

kill -STOP $$

しかし、エディターからシェルにジャンプした場合は、悲惨なことになります。すべてがそこに留まります。

タイピングの危険があるので、ニーモニック -KILL などを使用しがちです。

kill - 9 pid # note the space

昔は init を強制終了してしまうため、マシンをダウンさせることがありました。

于 2009-03-29T09:22:09.053 に答える
-1

ジョブはbashスクリプトで機能します

しかし、あなたは...次のようなスポーンされたスタッフを監視する必要があります:

ls -1 /usr/share/doc/ | while read -r doc ; do ... done

|の両側でジョブのコンテキストが異なります。

これをバイパスすると、whileの代わりにforが使用される可能性があります。

for `ls -1 /usr/share/doc` ; do ... done

これは、スクリプトでジョブを使用する方法を示しているはずです...私のコメントされたメモは... REAL(なぜその振る舞いなのかわからない)

    #!/bin/bash


for i in `seq 7` ; do ( sleep 100 ) &  done

jobs

while [ `jobs | wc -l` -ne 0 ] ; do

    for jobnr in `jobs | awk '{print $1}' | cut -d\[ -f2- |cut -d\] -f1` ; do
        kill %$jobnr
    done
    #this is REALLY ODD ... but while won't exit without this ... dunno why
    jobs >/dev/null 2>/dev/null
done

sleep 1
jobs
于 2012-05-24T11:29:49.727 に答える