web-dev-qa-db-ja.com

ターミナルを閉じずに、ターミナルで実行中のスクリプトを強制終了するには(Ctrl + Cは機能しません)?

他のいくつかのプログラムを呼び出し、一連のコマンドを実行するbashスクリプトを作成しました。このスクリプトを端末から実行します。次に、スクリプトを強制終了します。

Ctrl + Cを押してもカットされないことがあります。スクリプトが別のプログラムを実行していることがあり、何らかの理由でキル信号が機能しないためだと思います。

ただし、ターミナルウィンドウを閉じると、スクリプトが強制終了されます。

できることはありますか(キーボードの組み合わせ)、それは実際に端末ウィンドウを閉じずに端末ウィンドウを閉じることに似ています(コマンド履歴、現在のディレクトリ、出力履歴などを失いたくない)?

35
becko

選択肢はほとんどありません。 1つは、スクリプトを停止することです(CtrlZ)、スクリプトのPIDを取得し、プロセスグループに SIGKILL を送信します。

コマンドがシェルで実行されると、コマンドが開始するプロセスとそのすべての子は同じ process group (この場合、フォアグラウンドプロセスグループ)。このグループのすべてのプロセスに信号を送信するには、プロセスリーダーに送信します。 kill コマンドの場合、プロセスリーダーは次のように示されます。

kill -PID

ここで、PIDはスクリプトのプロセスIDです。

例:

いくつかのプロセスを起動するスクリプトtest.shを考えてください。シェルで実行したとしましょう:

$ ./test.sh

別の端末で、

$ pgrep test.sh
17802
$ pstree -ps `!!`
pstree -ps `pgrep test.sh`
init(1)───sshd(1211)───sshd(17312)───sshd(17372)───zsh(17788)───test.sh(17802)─┬─dd(17804)
                                                                               ├─sleep(17805)
                                                                               └─yes(17803)

この場合、test.shによって作成されたプロセスグループにシグナルを送信するには、次のようにします。

kill -INT -17802

-INTSIGINTの送信に使用されるため、このコマンドは CtrlC ターミナルで。 SIGKILLを送信するには:

kill -KILL -17802

別の端末を開くことができない場合にのみ、スクリプトを停止する必要があります。可能であれば、pgrepを使用してPIDを見つけます。

スクリプトが起動するコマンドの1つがSIGINTをトラップしている可能性があります。 CtrlC 効果がありません。ただし、SIGKILLはトラップできず、通常はlast-resortオプションです。キルする前にSIGTERM-TERM)を試してみるとよいでしょう。 SIGKILLSIGTERMも、SIGINTのように キーボードショートカット として設定できません。

スクリプトにShebang行が含まれていない場合、これはすべて意味がありません。 this SO answer :から

通常、親シェルは、同じシェル用にスクリプトが記述されていると推測します(最小限のBourneのようなシェルは/ bin/shでスクリプトを実行し、bashはbashサブプロセスとして実行します)...

このため、スクリプトの実行時に、スクリプトにちなんで名付けられたプロセス(またはコマンドラインでスクリプトの名前を持つプロセス)が見つからず、pgrepは失敗します。

常にシバンラインを使用してください。

38
muru

スクリプトに関連付けられているプロセスがわかっている場合は、次を使用してPIDを見つけることができます

 ps -A

次に、PID番号を使用して、対応するプロセスを強制終了します。

 kill -9 PID_Number
6
Harris

ハリスが言ったように、Kill -9 PID_Numberを実行できますが、htopと呼ばれるパッケージをインストールして、特定のプロセスを簡単に見つけることができるインタラクティブなプロセスブラウザーを使用することもできます。 htopはプロセスの強制終了もサポートしています。