nohup付け忘れた時disown -hでSIGHUPは防げるけど標準出力は死ぬことがある

  • Bash
  • Shell
  • Linux

この記事は、構成と文章の整理にAIを使っています。
あくまで読みやすくするための補助で、内容そのものをAIにすべて任せて書いているわけではありませんが、ところどころ相談しながら整えています。

nohupを付け忘れて長時間コマンドを実行し始めてしまった時、後からバックグラウンド化して端末を閉じても生かし続ける方法。

手順

  1. Ctrl+Z で実行中のプロセスを一時停止する(SIGTSTPが送られる)
  2. bg で停止中のジョブをバックグラウンドで再開する
  3. disown -h [jobspec] でジョブテーブルからは残しつつ、そのプロセスにSIGHUPが送られないようにする

disown は本来 -h を付けずに使うとジョブテーブルから完全に消えて、jobs / fg / bg の対象外になる。-h を付けた場合はジョブとして管理下には残したまま、HUPシグナルだけ無視させる指定になる。

端末を閉じる(=シェルが終了する)と、その端末から起動した子プロセスにはSIGHUPが飛ぶ。disown -h はこれを無視させることで、端末を閉じてもプロセスが死なないようにする、という理屈。

nohupと同じではない

disown -h はSIGHUPを無視させるだけで、nohup と完全に同じ効果ではない。

nohup は追加で標準出力・標準エラーの向き先を変える(デフォルトでは nohup.out にリダイレクトする)。一方で disown -h だけの場合、標準出力・標準エラーは元の端末(tty)に繋がったまま。

端末を閉じた後もそのプロセスが標準出力に書き込もうとすると、書き込み先のパイプ/ttyが既に閉じているため SIGPIPE を受けて死ぬことがある。特に進捗ログをガンガン吐くようなコマンドだと危ない。

対策

事前にリダイレクトしてから disown -h する方が安全。

ターミナル
command > output.log 2>&1 &
disown -h %1

こうしておけば出力先はファイルに固定されるので、端末を閉じても書き込み先が消えることはない。

nohup付け忘れに気づいた時点で既に標準出力・標準エラーが端末に繋がったまま動いている場合、後からリダイレクト先を変える方法(exec で再割り当てするなど)もあるが、確実性でいえば最初から nohup するか、リダイレクト済みで実行し直す方が早い。