【Linux】nohupの使い方|SSH切断でコマンドが止まる理由とdisownとの違い

【Linux】nohupの使い方|SSH切断でコマンドが止まる理由とdisownとの違い Linux

SSHでサーバーに接続し、時間のかかる処理(大量データの変換、バックアップ、ビルドなど)を実行しているとき、SSH接続が切れると実行中のコマンドも一緒に終了してしまう——これは多くの人が一度は経験する現象です。原因は、SSHセッションが切れると実行中のプロセスにSIGHUP(ハングアップ信号)が送られ、多くのコマンドはこれを受け取ると終了するためです。nohup(no hang up)は、このSIGHUPを無視させることで、SSHを切断しても処理を継続させるための定番コマンドです。

この記事では、実際のレンタルサーバーへのSSH接続を使い、本当にSSH切断でプロセスが死ぬのか、nohupを付けると生き残るのかを実際に確かめます。あわせて、似たような目的で使われるdisownとの違いについても、実際に検証した結果を紹介します。

先に結論

  • SSHが切れると、実行中のプロセスにSIGHUPが送られ、通常は終了します。
  • nohup コマンド &にすると、SIGHUPを無視してSSH切断後も処理を継続できます。
  • 出力は既定でnohup.outというファイルに自動で保存されます。
  • disownは「シェルの管理下から外す」機能で、SSHセッション終了時の挙動に対してはnohupほど確実ではありません(実際に検証済み)。
  • setsid コマンドも、新しいセッションを作ることでSSH切断から独立させられます。
  • 長時間の処理をSSH越しに実行するときは、最初からnohupを付けて起動するのが安全です。

実行中のプロセスを確認・終了する方法はps・kill、SSH接続の基本はscpコマンド~/.ssh/configもあわせて参考になります。

スポンサーリンク

【実証】SSH切断でコマンドが本当に死ぬのか

まず、nohupを使わずに実際のサーバー上でバックグラウンドジョブを起動し、SSH接続を切ってから改めて確認してみます。

nohupなしでSSH切断すると…
# SSH接続してバックグラウンドでコマンドを起動し、そのまま切断する
ssh user@server "sleep 30 &"
# (コマンドが返ってきた時点でSSH接続は終わる)

# 少し待ってから、別のSSH接続でプロセスを確認
ssh user@server "ps aux | grep sleep"
# → 何も表示されない(プロセスが消えている)
nohupなしだとSSH切断でプロセスが消える(実証)

実際のレンタルサーバーで、sleep 30 &を実行してすぐにSSH接続を終了し、数秒後に別のSSH接続からps auxで確認したところ、そのプロセスは跡形もなく消えていましたssh user@server "コマンド"という形でコマンドを実行すると、コマンドの終了と同時にSSHのセッションも終了し、そこで実行していたプロセスにSIGHUPが送られます。sleepのような多くのコマンドはSIGHUPを受け取ると、途中であっても終了してしまいます。「バックグラウンドで&を付けたのに、SSHを切ったら止まっていた」という現象は、まさにこれが原因です。

【実証】nohupを付けると生き残る

同じ操作を、今度はnohupを付けて行います。書き方はnohup コマンド &です(&でバックグラウンド実行にするのも忘れずに)。

nohupを付けて起動
# nohup を付けてバックグラウンドで起動
ssh user@server "nohup sleep 30 > nohup.out 2>&1 &"
# (コマンドが返ってきた時点でSSH接続は終わる)

# 別のSSH接続でプロセスを確認
ssh user@server "ps aux | grep sleep"
# user  3492607  0.0  0.0 107972   724 ?  S  08:36  0:00 sleep 30
#   ↑ TTY欄が「?」=制御端末なしで、ちゃんと生きている

実際のサーバーで、nohup sleep 30 > nohup.out 2>&1 &としてから同様にSSH接続を切り、別接続から確認したところ、今度はsleep 30プロセスがちゃんと生きたままps auxに表示されました。TTY列が?になっているのは、制御端末(元のSSHセッション)から完全に切り離されていることを示しています。さらに、出力先を指定しなくてもnohup.outというファイルが自動生成され、標準出力・標準エラーがそこに書き込まれることも確認しました。長時間かかる処理をSSH越しに実行するときは、最初からnohupを付けて起動するのが鉄則です。

【重要な発見】disownだけでは不十分だった

nohupと似た目的で紹介されることが多いのがdisownです。disownは「バックグラウンドジョブをシェルの管理下(ジョブテーブル)から外す」コマンドで、通常のログアウト時にシェルがジョブへSIGHUPを送るのを防ぎます。しかし、実際に検証したところ、SSHの非対話的なコマンド実行では、disownだけでは生き残りませんでした

disownでは生き残らなかった(実証)
# disown -h でジョブをシェルの管理下から外してから切断
ssh user@server "set -m; sleep 25 & disown -h %1"

# 別接続で確認すると…
ssh user@server "ps aux | grep sleep"
# → 何も表示されない(disownしても消えてしまった)
disownはnohupの代わりにならないケースがある(実証)

実際にset -mでジョブ制御を有効にしたうえでdisown -h %1を実行し、SSH接続を切って確認したところ、プロセスは生き残りませんでした。これは、disownが防げるのは「シェル自身が終了時に子ジョブへSIGHUPを送る」経路だけであり、SSHサーバー(sshd)がセッション終了時にそのセッションのプロセスへ直接SIGHUPを送る経路までは防げないためだと考えられます。一方nohupは、プロセス自身がSIGHUPを「無視する」よう設定されるため、信号がどこから送られてきても影響を受けません。この違いから、「SSH越しにコマンドを実行して切断後も残したい」という目的には、disownよりnohupのほうが確実だと言えます(対話的なターミナルでジョブをバックグラウンド化してからexitする、という異なる場面ではdisownが有効なこともあります)。

setsidという選択肢

setsidは、コマンドを新しいセッションのリーダーとして起動するコマンドです。元のセッション(SSH接続)から完全に独立するため、こちらもSSH切断後の生存に使えます。

setsid での起動
# setsid でコマンドを新しいセッションとして起動
ssh user@server "setsid sleep 25 < /dev/null > /dev/null 2>&1 &"

# 別接続で確認
ssh user@server "ps aux | grep sleep"
# user  3510364  0.0  0.0 107972   628 ?  Ss  08:40  0:00 sleep 25
#   ↑ 生きている(Ssはセッションリーダーであることを示す)

実際のサーバーでも、setsid sleep 25 < /dev/null > /dev/null 2>&1 &としたプロセスは、SSH切断後も生き残ることを確認しました(STAT列のSsは、独立したセッションのリーダーであることを示します)。nohupsetsidはアプローチが異なりますが(nohupは信号を無視、setsidはセッションごと独立させる)、どちらも実務では有効です。迷ったらnohupを使うのが、最もシンプルで広く知られた方法です。

主な書き方一覧

SSH切断からプロセスを守る方法をまとめます。

書き方 SSH切断後の生存
コマンド &(何もなし) × 死ぬ(実証)
nohup コマンド & ○ 生存(実証)
コマンド & disown -h × 死ぬ場合がある(実証)
setsid コマンド & ○ 生存(実証)
nohup.out nohupの既定の出力先

よくある失敗

SSHを切ったら処理が止まっていた

&だけではSIGHUPを防げません。nohupを付けて起動し直します。

disownを付けたのに切断で死んでしまう

SSHの非対話実行では、disownだけでは不十分なことがあります。nohupのほうが確実です。

nohup.outが肥大化する

出力先を明示的に指定(nohup コマンド > ログファイル 2>&1 &)すれば、場所や内容を管理しやすくなります。

ジョブが生きているか確認しない

ps aux | grep コマンド名で、実際に生きているか必ず確認します。

長時間処理を対話シェルで実行してしまう

最初からnohupを付けて起動する習慣をつけると、切断事故を防げます。

よくある質問

QSSHを切断すると実行中のコマンドが止まるのはなぜですか?
ASSHセッションが終了すると、そのセッションで実行していたプロセスにSIGHUP(ハングアップ信号)が送られるためです。多くのコマンドは、この信号を受け取ると途中であっても終了します。実際に検証したところ、nohupを付けずにバックグラウンド実行したプロセスは、SSH切断後すぐに消えていることを確認しています。
Qnohupはどう使いますか?
Anohup コマンド &のように、コマンドの前にnohupを付けてバックグラウンド実行します。実際にサーバー上で試したところ、SSHを切断してもプロセスが生き残り、標準出力・標準エラーは既定でnohup.outというファイルに自動保存されることを確認しています。
Qdisownとnohupの違いは何ですか?
Adisownはジョブをシェルの管理下から外し、シェル自身が終了時に送るSIGHUPを防ぎます。一方nohupはプロセス自身がSIGHUPを無視するよう設定します。実際に検証したところ、SSHの非対話的なコマンド実行ではdisownだけでは生き残らないケースがあり、SSH越しの長時間処理にはnohupのほうが確実だと分かりました。
Qすでにバックグラウンドで動いているコマンドをあとからnohup扱いにできますか?
Anohupコマンド自体は起動時に付けるものなので、あとから同じようには付けられません。既に実行中のジョブをSIGHUPから守りたい場合はdisownを試す方法がありますが、この記事の検証結果のとおりSSH切断に対しては確実とは言えません。長時間の処理は、最初からnohupを付けて起動するのが安全です。
Qsetsidとnohupはどちらを使えばいいですか?
AどちらもSSH切断後の生存に使えることを実際に確認しています。nohupはSIGHUPを無視する仕組み、setsidは新しいセッションとして独立させる仕組みで、アプローチは異なりますが目的は同じです。広く知られていて書き方もシンプルなnohupを基本の選択肢にするとよいでしょう。

まとめ

  • SSH切断はプロセスにSIGHUPを送り、多くのコマンドはそれで終了します。
  • nohup コマンド &で、SIGHUPを無視してSSH切断後も処理を継続できます(実証済み)。
  • 出力は既定でnohup.outに保存されます。
  • disownだけではSSH切断時に不十分な場合があります(実証済み)。
  • setsidも有効な代替手段です。迷ったらnohupを使いましょう。

SSH越しの長時間処理は、「切断=処理が止まる」と考えて、最初からnohupを付けて起動するのが最も安全な習慣です。ps・killと組み合わせて、実行中のジョブの状態も定期的に確認しておきましょう。