Bashで新しいバックグラウンドプロセスのジョブIDをプログラムで取得する方法

Bashで新しいバックグラウンドプロセスのジョブIDをプログラムで取得する方法

Bashで始まるジョブのジョブIDをプログラムでどのように取得しますか&

バックグラウンドでジョブを開始し、対応するジョブ&IDとBash組み込みコマンド(たとえばfgbgなど)を使用してジョブkillと対話できます。

たとえば、私がこのようなことを始めた場合

yes > /dev/null &

その後、次のコマンドを使用してそのジョブを終了できます(ジョブがジョブID 1を取得すると仮定)。

kill %1

create a new jobを使用すると、&新しく作成されたジョブのジョブIDをプログラムでどのように取得できますか?


私はあなたが得ることができることを知っていますプロセス番号(ジョブIDではない)$!、特にジョブIDを取得する方法を知りたいです。

答え1

このコマンドは、jobs現在実行中のバックグラウンドジョブとそのIDを印刷します。

$ for i in {1..3}; do yes > /dev/null & done
[1] 3472564
[2] 3472565
[3] 3472566

$ jobs
[1]   Running                 yes > /dev/null &
[2]-  Running                 yes > /dev/null &
[3]+  Running                 yes > /dev/null &

したがって、まだ実行中の最後に開始されたジョブのIDを取得するには次のように表示されます。+、次のことができます(GNUを使用grep)。

$ jobs | grep -oP '\d(?=]\+)'
3

または、より携帯性に優れています。

$ jobs | sed -n 's/^\[\([0-9]*\)\]+.*/\1/p'

ただし、ジョブのいずれかを一時停止するとそのジョブが置き換えられるため、最後の行のみをインポート+することをお勧めします。

$ jobs | tail -n1 | cut -d' ' -f1 | tr -d '][+'
3

答え2

bashマニュアルから引用:

シェルでアクションを参照する方法はいくつかあります。 %文字はジョブ仕様(jobspec)を表します。ジョブ番号nは%nと呼ぶことができます。ジョブの開始に使用された名前のプレフィックスを使用するか、そのコマンドラインに表示されるサブストリングを使用してジョブを参照することもできます。たとえば、%ceは停止したce操作を表します。プレフィックスが複数のジョブと一致すると、bashはエラーを報告します。一方、%?ceを使用すると、コマンドラインにce文字列を含むすべての操作が表示されます。 bashは、部分文字列が複数の操作と一致する場合にエラーを報告します。 %% および %+ 記号は、現在のジョブ、つまりフォアグラウンドで停止した、またはバックグラウンドで開始した最後のジョブのシェルの概念を表します。 %- を使用して前の操作を参照できます。ジョブが1つしかない場合は、%+と%-の両方を使用してそのジョブを参照できます。ジョブ関連の出力 (例えば、jobs コマンドの出力) では、現在のジョブは常に + で表され、前のジョブは - で示されます。 単一%(付随するジョブ仕様なし)も現在のジョブを表します。

また、このコマンドはjobs -lジョブIDとPIDをリストしているため、$!一部のスクリプトを使用してPID(インポート)をジョブIDに変換できます。

答え3

cmd &ジョブ番号を再利用でき、プロセスIDとプロセスグループIDを再利用できます。呼び出し間でjob実行中のプロセスがcmd終了しないという保証はありません。

では通常、bashの出力をjobs後処理できません。

あなたが信じることができるのはそれ以来です。

A | B | C &

trapパイプが非同期で起動されていない場合は、$!実行を開始したプロセスのpidが含まれますC

実行中のプロセスAとその子孫(存在する場合)BC、ジョブ(ジョブ制御が有効な対話型シェル)に含まれます。シェルは最初の無料作業番号を選択します。ジョブは、他の保留中のジョブがない場合にのみ現在のジョブになります(// %+(または%%一部のシェルの引数でも呼び出されます))。%killfgbg

jobs -lBashでは、ジョブが認識しているプロセスIDとともにジョブがリストされます。終了したものまでリストしているようです(私のテストで実行されたものをリストするのはtrueバグのように見えます)、そこから見ることができます。しかし、これを安定して行うことは不可能です。Runningsleep 100 | true$!

zsh$jobstatesキーがジョブIDと値である特別な連想配列を使用すると、より良い運を享受できます。running:+:37632=running:37633=done

job_id=${(k)jobstates[(R)*:$!=*]}

ここで値が見つかった要素が見つかります:$!=。可能性はリーンですが、プロセスが終了し、その親が終了を確認した後、両方の操作が同じpidを持つことは不可能ではないことに注意してください。

これを行った後、job_idjob_idが再利用される可能性が高いので、それを使用する前に、バックグラウンドで他のタスクが開始または一時停止されていないことを確認する必要があります。

ジョブIDに依存するのではなく、ジョブ名に一意の文字列を挿入して参照できます%?that-string

たとえば、

sleep 100 | sleep 101 $(: first) &
sleep 123 | sleep 123 $(: second) &
kill '%?first'

プロセスの実行中にジョブが終了しますsleep 100sleep 101ジョブが実行中で実行中に両方のプロセスが終了すると、エラーがkill発生します。kill: %?first: no such job

関連情報