Linuxでnohupコマンドを使用する方法

Linuxのnohupコマンドを使用すると、それらを起動した端末ウィンドウが閉じられても、重要なプロセスを実行し続けることができます。今日のLinuxでこの由緒あるコマンドを使用する方法をご紹介します。

HUPとSIGHUP

Linuxの祖先であるUnixは、PCが発明される前に作成されました。コンピュータは大きく、高価な機器でした。人々は、同じ建物内にある端末でローカルに、または遅いモデム接続でリモートに、シリアル回線を通じてコンピュータとやり取りしていました。当初、彼らはテレプリンターに指示を入力しており、それらは徐々に端末に置き換えられました。

処理能力が接続しているコンピュータにあり、入力している端末にはなかったため、端末は「端末」と呼ばれていました。プログラムはコンピュータ(それがどこに設置されていても)で実行されており、デスク上のデバイスでは実行されていませんでした。

端末とコンピュータの接続が切断されるようなことが起こると、コンピュータは回線の切断を検出し、実行していたプログラムに

<code>HUP</code>

またはハングアップシグナルを送信します。プログラムは、シグナルを受信すると実行を停止します。

その機能は、今日のLinuxでも存続しています。PCでは、端末ウィンドウは物理端末のエミュレーションです。その端末ウィンドウから起動されたプロセスが実行されていて、そのウィンドウを閉じると

<code>SIGHUP</code>

シグナルがプログラムに送信され、

<code>HUP</code>

が通知され、終了する必要があることを認識します。

連鎖効果が発生します。プロセスが子プロセスを起動した場合、SIGHUPもそれらに渡され、終了する必要があることを認識します。

nohupコマンドは子プロセスを起動しますが、

<code>SIGHUP</code>

シグナルを渡すことを拒否します。これは問題のように聞こえるかもしれませんが、実際には便利な機能です。

nohupコマンド

端末ウィンドウが閉じられた場合でもプロセスを継続させたい場合は、

<code>SIGHUP</code>

を傍受する方法が必要なので、プログラムがそれを受信しません。(実際、端末ウィンドウはプロセスを起動しません。それらは端末ウィンドウ内のシェルセッションによって起動されます。)その問題に対するシンプルでエレガントな解決策は、シェルセッションとプログラムの間に別のプロセスを配置し、その中間層のプログラムが

<code>SIGHUP</code>

シグナルを渡さないようにすることです。

それがnohupの機能です。nohupはプログラムを起動して、それらがnohupの子プロセスになり、シェルのプロセスにならないようにします。それらがシェルのプロセスではないため、シェルから直接

<code>SIGHUP</code>

を受信しません。また、nohup

<code>SIGHUP</code>

を子に渡さない場合、プログラムは

<code>SIGHUP</code>

を受信しません。

これは、たとえば、完了まで実行する必要がある長時間実行されるプロセスがある場合に便利です。端末ウィンドウとそのシェルを誤って閉じると、プロセスも終了します。nohupを使用してプロセスを起動すると、プロセスはnohupシグナルから分離されます。SSHを介してコンピュータでリモート作業を行っていて、リモート接続が失敗した場合に機密プロセスが終了しないようにしたい場合は、nohupを使用してリモートコンピュータでプロセスを開始します。

nohupを使用する

役に立たないプログラムを作成しましたが、終了されるまで実行され続けます。3秒ごとに端末ウィンドウに時刻を出力します。「long process」の略で

<code>long-proc</code>

と呼ばれます。

./long-proc

これが何か役に立つことを行うプログラムで、端末ウィンドウとシェルが閉じられても実行を継続させたい場合は、nohupで起動します。

nohup ./long-proc

このプロセスはstdinstdoutから切り離されているため、入力を受け取ることも、端末ウィンドウに書き込むこともできません。また、まだ実行中であるため、コマンドプロンプトに戻りません。nohupが行うことは、プロセスを端末の閉鎖の影響を受けないようにすることだけです。プロセスをバックグラウンドタスクにはしません。

プロセスを終了させるために再起動する必要がありますか?いいえ。バックグラウンドプロセスとして起動していないnohupプロセスを停止するには、Ctrl+Cキーの組み合わせを押します。

プログラムからの出力が「nohup.out」というファイルにキャプチャされました。lessで確認できます。

less nohup.out

通常、端末ウィンドウに送信されるものはすべてファイルにキャプチャされます。nohupの以降の実行は、既存の「nohup.out」ファイルに追加されます。

プロセスを実行するより便利な方法は、nohupで起動して端末ウィンドウを閉じても耐えられるようにし、同時にバックグラウンドタスクにすることです。これを行うには、コマンドラインの末尾にアンパサンド「&」を追加します。

nohup ./long-proc &

コマンドプロンプトに戻るには、もう一度「Enter」を押す必要があります。プロセスのジョブ番号は1(角括弧「[]」内の番号)で、プロセスIDは13115であることがわかります。

これらのいずれかを使用してプロセスを終了できます。「Ctrl+C」は、プログラムが端末ウィンドウまたはシェルと関連付けられていないため、今は機能しません。

ジョブ番号を忘れた場合は、jobsコマンドを使用して、その端末ウィンドウから起動されたバックグラウンドタスクを一覧表示できます。

jobs

タスクを終了するには、killコマンドと、パーセント記号「%」を前に付けたジョブ番号を使用します。このようになります。

kill %1

端末ウィンドウを閉じた場合は、プロセスIDを見つけて、それをkillコマンドで使用します。pgrepコマンドは、指定した検索手がかりに一致するプロセスのプロセスIDを見つけます。プロセス名で検索します。

pgrep long-proc

これで、プロセスIDを使用してプロセスを終了できます。

kill 13115

次に「Enter」を押すと、プロセスが終了したことが通知されます。

では、プロセスを終了させないものは何かを見てみましょう。再起動してから、端末ウィンドウを閉じます。

nohup ./long-proc

新しい端末ウィンドウを開いてpgrepでプロセスを検索すると、まだ実行されていることがわかります。プロセスを起動した端末ウィンドウを閉じても効果はありません。

pgrep long-proc

nohupに複数のコマンドを渡すことは可能ですが、通常は別々に起動した方がよいでしょう。バックグラウンドジョブとして操作しやすくなります。コマンドは同時に実行されず、順番に実行されます。実行は同時ではなく、逐次です。同時に実行するには、別々に起動する必要があります。

とはいえ、一度に複数のプロセスを起動するには、nohupを使用してBashシェルを起動し、コマンドの文字列に-c(コマンド)オプションを使用します。一重引用符「'」を使用してコマンドリストを囲み、二重アンパサンド「&&」を使用してコマンドを区切ります。

nohup bash -c 'ls /bin && ls /sbin'

lessを使用して「nohup.out」ファイルを参照すると、最初のプロセスの出力、次に2番目のプロセスの出力が表示されます。

less nohup.out

両方のコマンドからの出力が「nohup.out」ファイルにキャプチャされました。相互に絡み合うことはなく、2番目のプロセスの出力は、1番目のプロセスが終了してから初めて開始されます。

「nohup.out」の代わりに独自のファイルを使用したい場合は、コマンドを任意のファイルにリダイレクトできます。

nohup bash -c 'ls /bin && ls /sbin' > myfile.txt

メッセージに「nohupo.outに出力を追加」ではなく、「stderrをstdoutにリダイレクト」と表示され、stdoutを「myfile.txt」ファイルにリダイレクトしていることに注意してください。

lessを使用して「myfile.txt」ファイルの中を確認できます。

less myfile.txt

前と同様に、両方のコマンドからの出力が含まれています。

ユーティリティの歴史が、まるで現代とは無関係であるかのように感じさせるのは皮肉なことです。nohupコマンドはその1つです。シリアル回線の切断に対処するために作成されたものは、信じられないほど強力なマシンを使用する今日のLinuxユーザーにとっても依然として有用です。