実行中のプロセスをnohupにするにはどうすればよいですか?


940

すでに長い間実行されているプロセスがあり、それを終了したくありません。

nohupに配置する方法(つまり、ターミナルを閉じても実行を継続させる方法)


29
同じ問題に直面している人にとって:入力yourExecutable &しても出力が画面に表示され続けCtrl+C、何も停止しないように見えても、画面が出力でスクロールされていて何が表示されていなくても、盲目的に入力disown;して押しEnterてください。あなたが入力しています。プロセスは否認され、プロセスが停止することなくターミナルを閉じることができます。
ナビゲーション

回答:


1367

bash のジョブコントロールを使用して、プロセスをバックグラウンドに送信します。

  1. Ctrl+ Zプログラムを停止(一時停止)してシェルに戻ります。
  2. bg バックグラウンドで実行します。
  3. disown -h [job-spec]ここで、[job-spec]はジョブ番号です(%1最初に実行中のジョブの場合と同様です。jobsコマンドで自分の番号を見つけます)。これにより、ターミナルが閉じたときにジョブが強制終了されません。

38
質問は「nohupの下に置く」方法だったので、disown -hおそらくより正確な答えは次のとおりです。このシェルが開始したすべてのジョブ。」([ quantprinciple.com/invest/index.php/docs/tipsandtricks/unix/…から]
Jan-Philip Gehrcke博士、

8
後でジョブを回復するにはどうすればよいですか?ps -eを使用して実行されていることを確認できます。
Paulo Casaretto

26
disown、disownを実行するとジョブの出力が表示されないため、プロセスがデーモンになります。つまり、標準入出力が/ dev / nullにリダイレクトされます。したがって、ジョブを取り消す予定の場合は、ファイルにログインしてジョブを開始することをおmy_job_command | tee my_job.log
勧めし

8
'my_job_command | コマンドが既に実行された、my_job.logをteeしますか?
arod

23
disownプロセスからパイプの関連付けを解除します。パイプを再接続するgdbには、このスレッドで説明されているように使用します。より具体的には、この投稿
mbrownnyc 2013年

185

なんらかの理由でCtrl+ Zも機能していないとします。別の端末に移動し、プロセスIDを(を使用してps)見つけて実行します。

kill -SIGSTOP PID 
kill -SIGCONT PID

SIGSTOPプロセスを一時停止し、SIGCONTバックグラウンドで再開します。したがって、両方のターミナルを閉じてもプロセスは停止しません。


10
はい、これはOSの問題です。Windows上のCygwinではkillは機能しません。
Pungs 2013

6
また、ジョブが別のsshセッションから開始された場合にも非常に役立ちます。
Amir Ali Akbari 2014年

5
disown %1それを閉じる前に、最初のターミナルでを実行することを忘れないでください。
2014年

1
コンソールでグラフィカルインターフェイスを開始したので、これは便利です(私の場合kwin、クラッシュの後で、結果を考えずにkonsoleから開始しました)。したがって、kwinを停止すると、すべてがフリーズし、実行する可能性がなくなりますbg
Michele

@fred私はこれをしなかった、そしてそれは走り続けたようだった。可能ですか、それとも間違ったPIDをヒットしましたか?
誰も

91

実行中のジョブをシェルから分離するコマンド(=はそれをnohupにします)はdisown、基本的なシェルコマンドです。

bash-manpage(man bash)から:

否認[-ar] [-h] [jobspec ...]

オプションがない場合、各jobspecはアクティブなジョブのテーブルから削除されます。-hオプションを指定すると、各jobspecはテーブルから削除されませんが、シェルがSIGHUPを受信した場合にSIGHUPがジョブに送信されないようにマークされます。jobspecが存在せず、-aオプションも-rオプションも指定されていない場合、現在のジョブが使用されます。jobspecが指定されていない場合、-aオプションはすべてのジョブを削除またはマークすることを意味します。jobspec引数なしの-rオプションは、操作を実行中のジョブに制限します。jobspecが有効なジョブを指定しない限り、戻り値は0です。

つまり、単純な

disown -a

ジョブテーブルからすべてのジョブを削除し、nohupにします


9
disown -aすべてのジョブを削除します。シンプルdisownは現在のジョブを削除するだけです。答えのmanページが言うように。
Rune Schjellerup Philosof 14

73

これらは上記の良い答えです、私は明確化を追加したかっただけです:

あなたはdisownpidやプロセスをすることはできません、あなたdisownは仕事をします、そしてそれは重要な違いです。

ジョブは、シェルに接続されているプロセスの概念であるものです。そのため、ジョブを(中断するのではなく)バックグラウンドにスローして、破棄する必要があります。

問題:

%  jobs
[1]  running java 
[2]  suspended vi
%  disown %1

Unixジョブ制御の詳細については、http://www.quantprinciple.com/invest/index.php/docs/tipsandtricks/unix/jobcontrol/を参照してください


48

残念ながらdisownbashに固有であり、すべてのシェルで使用できるわけではありません。

Unixの特定の種類(AIXやSolarisなど)にはnohup、実行中のプロセスに適用できるコマンド自体のオプションがあります。

nohup -p pid

http://en.wikipedia.org/wiki/Nohupを参照してください


以下のためだけAIXSolaris。「AIXおよびSolarisバージョンのnohupには、将来のSIGHUPシグナルを無視するように実行中のプロセスを変更する-pオプションがあります。上記の非表示の組み込みbashとは異なり、nohup -pはプロセスIDを受け入れます。」出典
AlikElzin-kilaka

27

ノードの答えは本当に素晴らしいですが、それはどのようにstdoutとstderrをリダイレクトすることができるのかという疑問を残しました。UnixとLinuxで解決策を見つけましたが、完全ではありません。これら2つのソリューションをマージしたいと思います。ここにあります:

私のテストでは、loop.shと呼ばれる小さなbashスクリプトを作成しました。このスクリプトは、自身のpidを無限ループでのスリープ状態で出力します。

$./loop.sh

このプロセスのPIDをどうにかして取得します。通常ps -C loop.shは十分ですが、私の場合は印刷されています。

これで、別の端末に切り替えることができます(または、同じ端末で^ Zを押します)。これでgdb、このプロセスにアタッチされるはずです。

$ gdb -p <PID>

これにより、スクリプトが停止します(実行中の場合)。その状態によって確認することができるps -f <PID>場合、STATフィールドは「T +」(または^ Z「T」の場合)、どの手段(マニュアルPS(1))であります

    T Stopped, either by a job control signal or because it is being traced
    + is in the foreground process group

(gdb) call close(1)
$1 = 0

Close(1)は成功するとゼロを返します。

(gdb) call open("loop.out", 01102, 0600)
$6 = 1

Open(1)は、成功すると新しいファイル記述子を返します。

このオープンはと同じopen(path, O_TRUNC|O_CREAT|O_RDWR, S_IRUSR|S_IWUSR)です。の代わりにO_RDWR O_WRONLY適用できますが、/usr/sbin/lsofすべてのstd *ファイルハンドラー(FD列)に対して「u」と表示されますO_RDWR

/usr/include/bits/fcntl.hヘッダーファイルの値を確認しました。

出力ファイルはとO_APPEND同じようにで開くことができますが、NFSの問題が発生する可能性があるため、nohupでは推奨されませんman open(2)

戻り値として-1が返されるとcall perror("")、エラーメッセージが出力されます。errnoが必要な場合は、p errnogdbコマンドを使用してください。

これで、新しくリダイレ​​クトされたファイルを確認できます。/usr/sbin/lsof -p <PID>プリント:

loop.sh <PID> truey    1u   REG   0,26        0 15008411 /home/truey/loop.out

私たちが望むならば、我々が使用してする場合は、我々は、別のファイルに標準エラー出力をリダイレクトすることができますcall close(2)し、call open(...)再度、別のファイル名を使用して。

これで、添付bashファイルを解放する必要があり、終了できますgdb

(gdb) detach
Detaching from program: /bin/bash, process <PID>
(gdb) q

スクリプトがgdb他の端末から停止された場合、スクリプトは引き続き実行されます。loop.shのターミナルに切り替えることができます。画面には何も書き込まれませんが、実行されてファイルに書き込まれます。バックグラウンドに配置する必要があります。を押し^Zます。

^Z
[1]+  Stopped                 ./loop.sh

(これ^Zで、最初に押された場合と同じ状態になります。)

これで、ジョブの状態を確認できます。

$ ps -f 24522
UID        PID  PPID  C STIME TTY      STAT   TIME CMD
<UID>    <PID><PPID>  0 11:16 pts/36   S      0:00 /bin/bash ./loop.sh
$ jobs
[1]+  Stopped                 ./loop.sh

そのため、プロセスはバックグラウンドで実行され、ターミナルから切り離されている必要があります。jobs角括弧で囲まれたコマンドの出力の番号は、内のジョブを識別しbashます。bashジョブ番号の前に '%'記号を適用する次の組み込みコマンドで使用できます。

$ bg %1
[1]+ ./loop.sh &
$ disown -h %1
$ ps -f <PID>
UID        PID  PPID  C STIME TTY      STAT   TIME CMD
<UID>    <PID><PPID>  0 11:16 pts/36   S      0:00 /bin/bash ./loop.sh

これで、呼び出し側のbashを終了できます。プロセスはバックグラウンドで実行を続けます。PPIDを終了すると、1(init(1)プロセス)になり、制御端末が不明になります。

$ ps -f <PID>
UID        PID  PPID  C STIME TTY      STAT   TIME CMD
<UID>    <PID>     1  0 11:16 ?        S      0:00 /bin/bash ./loop.sh
$ /usr/bin/lsof -p <PID>
...
loop.sh <PID> truey    0u   CHR 136,36                38 /dev/pts/36 (deleted)
loop.sh <PID> truey    1u   REG   0,26     1127 15008411 /home/truey/loop.out
loop.sh <PID> truey    2u   CHR 136,36                38 /dev/pts/36 (deleted)

コメント

gdbのものを自動化して、コマンドとrunを含むファイル(loop.gdbなど)を作成できますgdb -q -x loop.gdb -p <PID>。私のloop.gdbは次のようになります:

call close(1)
call open("loop.out", 01102, 0600)
# call close(2)
# call open("loop.err", 01102, 0600)
detach
quit

または、代わりに次の1つのライナーを使用できます。

gdb -q -ex 'call close(1)' -ex 'call open("loop.out", 01102, 0600)' -ex detach -ex quit -p <PID>

これがソリューションのかなり完全な説明であることを願っています。


確かに非常に有益であり、単純なケースではうまく機能する可能性があります。ただし、より複雑なケースでは、惨めに失敗する可能性があります。今日私はそれらの1つを持っていました:私のプロセスは出力(おそらくstderrへの)を行う別のプロセスを起動しましたが、そのマスターとの通信のためにstdoutをフックしました。子がstderrを継承しており、子のstdoutを閉じると、パイプの反対側で待機していたマスターが失敗したため、マスターFDのリダイレクトは効果がありませんでした。X- | これを試す前に、Betternはプロセスをよく理解しています。
cmaster-モニカを2015年

@cmasterハンドルがリダイレクトされるかどうかを確認できlsofます(ファイルハンドルの名前はpipeでなく/dev/pts/1)またはby ls -l /proc/<PID>/fd/<fd>(これはハンドルのシンボリックリンクを示します)。また、サブプロセスはまだ出力をリダイレクトできない可能性があり、ファイルにリダイレクトする必要があります。
TrueY 2015

7

実行中のプロセスをnohupに送信するには(http://en.wikipedia.org/wiki/Nohup

nohup -p pid 、私にとってはうまくいきませんでした

それから私は次のコマンドを試してみましたが、それは非常にうまくいきました

  1. SOMECOMMANDを実行します/usr/bin/python /vol/scripts/python_scripts/retention_all_properties.py 1

  2. Ctrl+ Zプログラムを停止(一時停止)してシェルに戻ります。

  3. bg バックグラウンドで実行します。

  4. disown -h 端末が閉じたときにプロセスが強制終了されないようにします。

  5. exitシェルから抜けるにはタイプしてください。操作は独自のプロセスでバックグラウンドで実行され、シェルに結び付けられていないので、これで準備は完了です。

このプロセスは、を実行するのと同じですnohup SOMECOMMAND


3

私のAIXシステムで、私は試しました

nohup -p  processid>

これはうまくいきました。ターミナルウィンドウを閉じた後でも、プロセスが実行され続けました。デフォルトのシェルとしてkshがあるため、bgand disownコマンドは機能しませんでした。


2
  1. ctrl+ z -これはジョブを一時停止します(キャンセルされません!)
  2. bg -これにより、ジョブがバックグラウンドになり、実行中のプロセスに戻ります
  3. disown -a -これにより、すべての添付ファイルがジョブでカットされます(ターミナルを閉じても実行されます)

これらの簡単な手順により、プロセスを実行したままターミナルを閉じることができます。

それは上に置く習慣nohup(あなたの質問の私の理解に基づいて、あなたはここでそれを必要としません)。


disown -aの動作は、すべてのジョブの愛着を切ることだと思います。ただし、stdin / stdoutパイプラインはシャットダウンされません。つまり、プロセスは引き続きターミナルから書き込み(/読み取り)を
試み

-2

これは、tcshellでUbuntu Ubuntu linuxで動作しました。

  1. CtrlZ 一時停止します

  2. bg バックグラウンドで実行する

  3. jobs そのジョブ番号を取得する

  4. nohup %n ここで、nはジョブ番号です


2
いいえ、機能しません:nohup: failed to run command '%1': No such file or directory
Dunatotatos 2018年
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.