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

StackOverflow https://stackoverflow.com/questions/625409

  •  05-07-2019
  •  | 
  •  

質問

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

これを nohup の下に置くにはどうすればよいですか (つまり、ターミナルを閉じても実行を継続するにはどうすればよいですか?)

役に立ちましたか?

解決

bashのジョブコントロールを使用して、プロセスを背景:

  1. Ctrl + Z を押してプログラムを停止(一時停止)し、シェルに戻ります。
  2. bgバックグラウンドで実行します。
  3. 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

http://en.wikipedia.org/wiki/Nohup

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、私にとってはうまくいきませんでした

その後、次のコマンドを試してみましたが、非常にうまく機能しました

  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の実行と同等です。

AIXシステムで試しました

nohup -p  processid>

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

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

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

nohupは付けません(あなたの質問に対する私の理解に基づき、ここでは必要ありません)。

これは、tcshellを使用している間にUbuntu linuxで機能しました。

  1. Ctrl Z で一時停止

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

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

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

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top