如何将已经运行的进程放在nohup下?

我有一个进程已经运行了很长时间,不想结束它。

我如何把它放在nohup下(也就是说,即使我关闭终端,我如何使它继续运行?)

504477 次浏览

将正在运行的作业从shell中分离出来的命令是disown和一个基本的shell命令。

从bash-manpage(man bash):

disown[-ar][-h][jobspec…]

如果没有选项,每个jobspec都会从活动作业表中删除。如果给出-h选项,则每个jobspec都不会从表中删除,但标记为如果shell收到SIGHUP,则不会将SIGHUP发送到作业。如果没有jobspec存在,并且既不提供-a也不提供-r选项,则使用当前作业。如果没有提供jobspec,则使用-a选项表示删除或标记所有作业;没有jobspec参数的-r选项将操作限制为正在运行的作业。返回值为0,除非jobspec没有指定有效的作业。

这意味着,一个简单的

disown -a

将从作业表中删除所有作业并使其成为nohup

使用bash的作业控制将进程发送到后台:

  1. Ctrl+Z停止(暂停)程序并返回shell。
  2. bg在后台运行它。
  3. disown -h [job-spec],其中[job-spec]是作业编号(就像第一个正在运行的作业的%1;使用jobs命令查找您的编号),以便在终端关闭时作业不会被杀死。

这些都是很好的答案,我只是想澄清一下:

你不能disown一个pid或进程,你disown一份工作,这是一个重要的区别。

作业是附加在shell上的进程的概念,因此您必须将作业扔进后台(而不是挂起它),然后放弃它。

问题:

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

请参见http://www.quantprinciple.com/invest/index.php/docs/tipsandtricks/unix/jobcontrol/有关Unix作业控制的更详细讨论。

假设由于某种原因Ctrl+Z也不起作用,转到另一个终端,找到进程ID(使用ps)并运行:

kill -SIGSTOP PIDkill -SIGCONT PID

SIGSTOP将暂停进程,SIGCONT将在后台恢复进程。所以现在,关闭两个终端不会停止您的进程。

不幸的是,disown特定于bash,并不能在所有shell中使用。

某些风格的Unix(例如AIX和Solaris)在nohup命令本身上有一个选项,可以应用于正在运行的进程:

nohup -p pid

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

将正在运行的进程发送到nohup(http://en.wikipedia.org/wiki/Nohup

nohup -p pid,它对我不起作用

然后我尝试了以下命令,效果非常好

  1. 运行一些人,/usr/bin/python /vol/scripts/python_scripts/retention_all_properties.py 1.

  2. Ctrl+Z停止(暂停)程序并返回shell。

  3. bg在后台运行它。

  4. disown -h,以便在终端关闭时不会杀死进程。

  5. 键入exit以退出shell,因为现在您可以开始了,因为操作将在其自己的进程中在后台运行,因此它不会被绑定到shell。

这个过程相当于运行nohup SOMECOMMAND

在我的AIX系统上,我尝试过

nohup -p  processid>

这工作得很好。即使在关闭终端窗口后,它仍继续运行我的进程。我们将ksh作为默认shell,因此bgdisown命令不起作用。

Node的答案真的很棒,但它留下了如何重定向stdout和stderr的问题。我在Unix&Linux上找到了一个解决方案,但它也不完整。我想合并这两个解决方案。这里是:

对于我的测试,我制作了一个名为loop.sh的小型bash脚本,它在无限循环中打印自身的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

关闭(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打开,就像nohup所做的那样,但man open(2)不建议这样做,因为可能存在NFS问题。

如果我们得到-1作为返回值,那么call perror("")会打印错误消息。如果我们需要errno,请使用p errno gdb comand。

现在我们可以检查新重定向的文件。/usr/sbin/lsof -p <PID>打印:

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

如果我们想使用不同的文件名再次使用call close(2)call open(...),我们可以将stderr重定向到另一个文件。

现在附加的bash必须被释放,我们可以退出gdb

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

如果脚本被gdb从另一个终端停止,它会继续运行。我们可以切换回loop.sh的终端。现在它不会在屏幕上写任何东西,而是运行并写入文件。我们必须把它放到后台。所以按^Z

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

(现在我们处于与开始时按下^Z相同的状态。

现在我们可以检查作业的状态:

$ ps -f 24522UID        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.outloop.sh <PID> truey    2u   CHR 136,36                38 /dev/pts/36 (deleted)

评论

可以自动创建包含命令的文件(例如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)detachquit

或者可以使用以下一个衬垫代替:

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

我希望这是对解决方案的一个相当完整的描述。

  1. ctrl+z-这将暂停作业(不会取消!)
  2. bg-这将把作业放在后台并返回正在运行的进程
  3. disown -a-这将删除所有带有作业的附件(所以你可以关闭终端,它仍然会运行)

这些简单的步骤将允许您在保持进程运行的同时关闭终端。

它不会放在nohup上(根据我对你问题的理解,你在这里不需要它)。

简单易行的步骤

  1. Ctrl + Z ---------->;暂停进程
  2. bg -------------->;恢复和运行后台
  3. disown %1 ------------->;仅当您需要从终端分离时才需要