Linuxでnohupコマンドを使ってバッチ処理(コマンド)を実行し続ける

nohupコマンドを使うことでターミナルを閉じてもバッチ処理(コマンド)を実行し続けることができます。

下のブログ記事が参考になるというか、何なら実行するには充分だと思います。
本記事ではnohupコマンドってなんだ?みたいな自分が疑問に思って調べたことを追記しておきます。

[Linux] Terminalを閉じてもバックグラウンドの処理を実行し続ける - nohup

nohupコマンドの使い道

nohupコマンドの使い道については先のブログでわかりやすかったので引用します。

Linuxでシステム運用をしていると、数時間〜数日間に及ぶバッチ処理を実行することがあります。手動でプログラムを起動する場合にディスプレイの前にずっと付きっきりでは過労死まっしぐらです。またうっかりTerminalを閉じてしまうと大惨事になってしまうため通常はバックグラウンドで実行します。

これに加えて、実例としてAWS Systems Manager Session Managerを使ってAWS EC2インスタンスに接続したとき、長時間操作がなかったり、サインインセッションが切れたりするとターミナルが閉じてしまいます。

何らかの原因でターミナルが閉じてしまうとコマンドが停止してしまうので、それを防ぐためにnohupコマンドを使います。

試した環境

以下ではLinuxコマンドを使って試しています。 利用した環境は以下のとおりです・

nohupコマンドの使い方

以下のように使います。

$ nohup {実行し続けたいコマンド} &

末尾の&は実行し続けたいコマンドをバックグラウンドで実行させることを意味します。バックグラウンドで実行していてもターミナルが閉じられると処理は停止してしまいます。
先頭のnohupによって、ターミナルが閉じても処理を停止しないようになります。

標準出力への出力はコマンドを実行したディレクトリにnohup.outというファイルが作成され、そこに追記されていきます。 標準エラー出力は標準出力にリダイレクトされているため、nohup.outに追記されます。

実際の例を見てみます。

sleepコマンドは指定された秒数だけ待機するコマンドのため、$ sleep 10というようにターミナルでそのまま実行すると10秒後にプロンプトが返ってきます。

以下のように実施すると、バックグラウンドで実行されるため、プロンプトはすぐに返ってきます。
また、現在のディレクトリにnohup.outというファイルが作成されているはずです(標準出力される内容が存在しないため、空ファイルです)。

$ nohup sleep 10 &

出力先をnohup.outから別のファイルにする

方法は、manコマンドに書かれており、リダイレクトでファイル名を指定するだけです。

To save output to FILE, use 'nohup COMMAND > FILE'.

$ nohup {実行し続けたいコマンド} > {出力先ファイル} &

実例で試してみます。sleepコマンドだけでは標準出力に何も出てこないのでechoを使って確認してみます。

mycommand.shというファイルを作成し、以下の内容を記述しておきます。 このスクリプトファイルが実行されると、startと現在日時が出力され、5秒後にfinと現在日時が出力されます。

#!/bin/bash
echo 'start' `date`
sleep 5
echo 'fin' `date`

nohupコマンドでこのスクリプトファイルを実行してみます。

$ nohup sh ./mycommand.sh &

カレントディレクトリにnohup.outが作成され、以下のようになっています。

start Fri Aug 10 00:00:01 JST 2023
fin Fri Aug 10 00:00:06 JST 2023

同じコマンドを再度実行すると、nohup.outに追記されます。

start Fri Aug 10 00:00:01 JST 2023
fin Fri Aug 10 00:00:06 JST 2023
start Fri Aug 10 00:14:24 JST 2023
fin Fri Aug 10 00:14:29 JST 2023

一度nohup.outを削除し、出力先ファイルをmyout.outに変更してみます。

$ nohup sh ./mycommand.sh > myout.out &

カレントディレクトリを確認してみると、nohup.outは存在していません。代わりにmyout.outが作成されています。 内容は先程のnohup.outと同じようになります。

start Fri Aug 10 00:23:36 JST 2023
fin Fri Aug 10 00:23:41 JST 2023

バックグラウンドで実行されている処理(コマンド、ジョブ)を確認する

&を使うことでコマンドをバックグラウンドで実行できることは既に紹介しています。 ここではバックグラウンドで実行されている処理がいくつあるのかを確認するjobsコマンドを見ていきます。

$ nohup sleep 10 &
$ jobs
[1]+  Running                 nohup sleep 10 &

jobsコマンドによってジョブ一覧が表示され、それぞれのジョブ番号と実行状態と処理の内容が確認できます。

ジョブとプロセス

『新しいLinuxの教科書』によれば、

プロセスは、Linuxカーネルから見た処理の単位でした。これに対して。シェルから見た処理の単位をジョブと呼びます。

ということであり、今回ジョブの一覧を見るにはjobsコマンドが使えます。

バックグラウンドからフォアグラウンドに戻す

実行したジョブを途中で停止したいときや、シェルを使って対話的に操作したいときには、ジョブをバックグラウンドからフォアグラウンドに戻します。

このときにはfgコマンドを使います。fgコマンドはjobsコマンドで見たジョブ番号を使います。

$ fg {ジョブ番号}

もしくは

$ fg %{ジョブ番号}

実際の例です。

$ nohup sleep 30 &
$ jobs
[1]+  Running                 nohup sleep 30 &
$ fg 1
nohup sleep 30

フォアグラウンドからバックグラウンドに戻す

今度は逆にジョブをフォアグラウンドからバックグラウンドに戻します。

使うコマンドはbgコマンドです。使い方はfgコマンドと同じです。

$ bg {ジョブ番号}

もしくは

$ bg %{ジョブ番号}

実際の例です。
nohupコマンドをバックグラウンドで実行し、fgコマンドでフォアグラウンドに戻します。Ctrl + Z(^Zの部分)でジョブを停止し、bgコマンドでバックグラウンドで処理を再開させます。

$ nohup sleep 30 &
$ jobs
[1]+  Running                 nohup sleep 30 &
$ fg 1
nohup sleep 30
^Z
$ jobs
[1]+  Stopped                 nohup sleep 30 &
$ bg 1

nohupはSIGHUPを受け付けないという意味

ターミナルが終了するさいに、ジョブはSIGHUP(ハングアップ、Hang up)というシグナルを受け取って終了します。

nohupはこのSIGHUPを受け取っても停止しないようにするためのコマンドです。
NO Hang UPで覚えれば忘れないはず。

参考サイト・文献