bashスクリプトの実行後にターミナルを終了する

gnome-openコマンドを使って特定のファイル(主にpdfファイル)を開くbash`スクリプトを書こうとしています。また、pdfファイルを開いたらターミナルを終了させたいと思っています。

スクリプトの最後に exit を追加してみましたが、ターミナルは閉じませんでした。私の質問に対する答えをオンラインで検索しようとしましたが、適切なものが見つかりませんでしたので、皆様のお力添えをいただければ幸いです。

全てのターミナルではなく、コマンドを実行したターミナルだけを殺すような回答が必要なのですが、可能でしょうか?私が受け入れた前の回答では、開いているすべてのターミナルウィンドウが殺されていました。今日までこのようなことがあるとは知りませんでした。

ソリューション

なぜなら、スクリプトは複数のコマンドを連続して実行するための簡単な方法であり、ここでは2つのコマンド(exitを含む)を実行するだけでよいからです。

もし、exit をコマンドの後や一連のコマンドの後に実行したい場合は、&& 演算子(前のコマンドや一連のコマンドが成功すると次のコマンドが実行される)や ; 演算子(前のコマンドや一連のコマンドが成功しても失敗しても次のコマンドが実行される)を使うことで、既に実行しているコマンドに連鎖させることができます。

この場合は次のようになります。

gnome-open <path_to_pdf_file> && exit

*<path_to_pfd_file> = pdfファイルのパス

スクリプトの最後に exit を書いても、スクリプトを実行した bash インスタンスを終了するだけなので、うまくいきません。bash インスタンスは、Terminal の内側の bash インスタンスとは別の bash インスタンスです。

スクリプトを使用したい場合、最も簡単な方法は、次のようにスクリプトを呼び出すことです。

<path_to_script> && exit

また、そのスクリプトが Terminal のカレントワーキングディレクトリにある場合は、次のようにします。

./<script> && exit

もし、どうしてもそうしたくない、できないという場合は、2番目に簡単な方法として、スクリプトの最後に次の行を追加することができます。

kill -9 $PPID

これにより、スクリプトの親プロセス(ターミナルにリンクされている bash インスタンス)に SIGKILL シグナルが送信されます。Terminalにリンクされているbashインスタンスが1つだけの場合は、それが殺されるとTerminal自体が終了します。複数の bash インスタンスが Terminal にリンクされている場合、そのインスタンスが殺されても、Terminal は自身を閉じることはありません。

解説 (4)

このスクリプトは、ターミナル、ひいてはシェルと自分自身を終了させます。

すべてのプロセスを容赦なく終了させます。ターミナルで複数のタブを開いている場合は、それらも閉じられます

*問題は、複数のターミナルが開かれていて、それらが gnome-terminal-server の子プロセスである場合、すべてのターミナルが殺されてしまうことです。

*このような場合、スクリプトは独立したターミナル、例えばxtermで起動する必要があります。

 & disown

PPPID=$(awk '{print $4}' "/proc/$PPID/stat")
kill $PPPID
  • PPID

PPIDは親プロセスのIDで、ここではシェル(e.g. /bin/bash)を指します。

  • PPPID

PPPIDはPPIDの親プロセスIDで、この場合はターミナルウィンドウです。

  • & disown です。

bashシェルでは、組み込みコマンドdisownを使用して、ジョブテーブルからジョブを削除したり、親シェルがSIGHUPシグナルを受信した場合(ユーザーがログアウトした場合など)に、そのジョブにSIGHUPシグナルが送信されないようにマークしたりします。

  • awk '{print $4}' "/proc/$PPID/stat"

ファイル /proc/$PPID/stat の4列目の値を取得します(例:/proc/1/stat の場合は0を返します)。

解説 (17)

最もシンプルな解決策は

xdg-open file.pdf && exit

他の似たようなコマンドと違って、 nohup はコマンドが SIGHUP を無視するために必要ではありません。 理由は xdg-open が pdf ファイルを開くための優先アプリケーションである子プロセスを生成して終了するからです。ターミナルから起動された実際のプロセスはもはや殺されるべきものではないので、 nohup は必要ありません。

&& は、前のコマンドが成功した場合、つまり終了コード 0 ($?=0) を返した場合に、次のコマンドが実行されることを示し、exit は単にターミナルを閉じます。

解説 (11)