すでに実行中のプロセスを nohup の下に置くにはどうすればよいですか?
質問
すでに長時間実行されているプロセスがあり、それを終了したくありません。
これを nohup の下に置くにはどうすればよいですか (つまり、ターミナルを閉じても実行を継続するにはどうすればよいですか?)
解決
bashのジョブコントロールを使用して、プロセスを背景:
- Ctrl + Z を押してプログラムを停止(一時停止)し、シェルに戻ります。
-
bg
バックグラウンドで実行します。 -
disown -h [job-spec]
ここで、[job-spec]はジョブ番号です(最初に実行中のジョブの%1
など。jobs
コマンドで番号を検索します)。これにより、端末が閉じられてもジョブは強制終了されません。 。
他のヒント
何らかの理由で Ctrl + Z も機能していないと仮定し、別のターミナルに移動して、プロセスIDを見つけ(ps
を使用)、実行します:
kill -SIGSTOP PID
kill -SIGCONT PID
SIGSTOP
はプロセスを中断し、SIGCONT
はバックグラウンドでプロセスを再開します。そのため、両方の端末を閉じてもプロセスは停止しません。
実行中のジョブをシェルから分離するコマンド(= nohupにする)は、disown
および基本的なシェルコマンドです。
bash-manpage(man bash)から:
disown [-ar] [-h] [jobspec ...]
オプションなしで、各jobspecはアクティブなジョブのテーブルから削除されます。 -hオプションが指定されている場合、各jobspecは テーブルから削除されますが、シェルがSIGHUPを受信した場合にSIGHUPがジョブに送信されないようにマークされています。 jobspecがない場合 存在し、-aオプションも-rオプションも指定されていない場合、現在のジョブが使用されます。 jobspecが指定されていない場合、-aオプション すべてのジョブを削除またはマークすることを意味します。 jobspec引数なしの-rオプションは、実行中のジョブに操作を制限します。リターン jobspecで有効なジョブが指定されていない限り、値は0です。
つまり、シンプルな
disown -a
ジョブテーブルからすべてのジョブを削除し、それらをnohupにします
これらは上記の良い回答です。説明を追加したいだけです。
pidまたはプロセスをdisown
することはできません。<=>ジョブを実行することは重要な違いです。
ジョブとは、シェルにアタッチされたプロセスの概念であるため、ジョブをバックグラウンドに(サスペンドではなく)スローし、それを否認する必要があります。
問題:
% jobs
[1] running java
[2] suspended vi
% disown %1
http://www.quantprinciple.com/をご覧ください。 invest / index.php / docs / tipsandtricks / unix / jobcontrol / Unix Job Controlの詳細については、
残念ながらdisown
はbashに固有であり、すべてのシェルで使用できるわけではありません。
特定の種類のUnix(AIXやSolarisなど)には、実行中のプロセスに適用できるnohup
コマンド自体のオプションがあります:
nohup -p pid
Nodeの答えは本当に素晴らしいですが、stdoutとstderrをどのようにリダイレクトできるかという疑問が残されました。で解決策を見つけました ユニックスとリナックス, しかし、それも完全ではありません。これら 2 つのソリューションを統合したいと思います。ここにあります:
私のテストでは、loop.sh という小さな bash スクリプトを作成しました。これは、無限ループで 1 分間スリープして自身の PID を出力します。
$./loop.sh
次に、何らかの方法でこのプロセスの PID を取得します。いつもの ps -C loop.sh
これで十分ですが、私の場合は印刷されてしまいます。
これで、別の端末に切り替えることができます (または、同じ端末で ^Z を押します)。今 gdb
このプロセスにアタッチする必要があります。
$ gdb -p <PID>
これにより、スクリプトが停止します (実行中の場合)。その状態は次のようにして確認できます ps -f <PID>
, 、 どこ STAT
フィールドは 'T+' (または ^Z の場合は 'T') で、これは (man 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) は、成功すると 0 を返します。
(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* ファイル ハンドラーに対して「u」と表示します (FD
列)、つまり O_RDWR
.
/usr/include/bits/fcntl.h ヘッダー ファイルの値を確認しました。
出力ファイルは次のように開くことができます O_APPEND
, 、 として nohup
するかもしれませんが、これは推奨されていません man open(2)
, NFS に問題がある可能性があるためです。
戻り値として -1 が返された場合、 call perror("")
エラーメッセージを出力します。errno が必要な場合は、次を使用します p errno
gdbコマンド。
これで、新しくリダイレクトされたファイルを確認できるようになりました。 /usr/sbin/lsof -p <PID>
プリント:
loop.sh <PID> truey 1u REG 0,26 0 15008411 /home/truey/loop.out
必要に応じて、stderr を別のファイルにリダイレクトできます。 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 のものは、ファイルの作成を自動化できます (例: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
または、代わりに次のワンライナーを使用することもできます。
gdb -q -ex 'call close(1)' -ex 'call open("loop.out", 01102, 0600)' -ex detach -ex quit -p <PID>
これがソリューションのかなり完全な説明であることを願っています。
実行中のプロセスをnohupに送信するには( http://en.wikipedia.org/wiki/Nohup)
nohup -p pid
、私にとってはうまくいきませんでした
その後、次のコマンドを試してみましたが、非常にうまく機能しました
-
いくつかのSOMECOMMANDを実行し、
/usr/bin/python /vol/scripts/python_scripts/retention_all_properties.py 1
と言います。 -
Ctrl + Z を押してプログラムを停止(一時停止)し、シェルに戻ります。
-
bg
バックグラウンドで実行します。 -
disown -h
ターミナルが閉じられたときにプロセスが強制終了されないようにします。 -
シェルから抜け出すには
exit
を入力します。これは、独自のプロセスで操作がバックグラウンドで実行されるので、シェルに関連付けられていないためです。
このプロセスは、nohup SOMECOMMAND
の実行と同等です。
AIXシステムで試しました
nohup -p processid>
これはうまくいきました。ターミナルウィンドウを閉じた後でも、プロセスを実行し続けました。デフォルトのシェルとしてkshがあるため、bg
およびdisown
コマンドは機能しませんでした。
- ctrl + z -これはジョブを一時停止します(キャンセルしません!)
-
bg
-これにより、ジョブがバックグラウンドになり、実行中のプロセスに戻ります -
disown -a
-これにより、ジョブの添付ファイルがすべてカットされます(したがって、ターミナルを閉じても実行されます)
これらの簡単な手順により、プロセスを実行したままターミナルを閉じることができます。
nohup
は付けません(あなたの質問に対する私の理解に基づき、ここでは必要ありません)。
これは、tcshellを使用している間にUbuntu linuxで機能しました。
-
Ctrl Z で一時停止
-
bg
バックグラウンドで実行するには -
jobs
ジョブ番号を取得する -
nohup %n
nはジョブ番号です