如何将已经运行的进程置于nohup下?


940

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

如何将其置于nohup下(即,即使关闭终端,如何使它继续运行?)


29
对于面临相同问题的任何人:请记住,即使您键入yourExecutable &并且输出不断出现在屏幕上,并且Ctrl+C似乎没有停止任何操作,即使屏幕正在滚动显示输出,您也只能盲目地键入disown;并按一下Enter,而您看不到什么您正在输入。该过程将被取消,您将可以关闭终端而该过程不会终止。
2016年

Answers:


1367

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

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

38
由于问题在于如何“将其置于nohup下”,因此disown -h可能是更准确的答案:“使disown行为更像nohup(即,作业将保留在当前shell的进程树中,直到退出shell)为止。这个Shell开始的所有工作。” (从[ quantprinciple.com/invest/index.php/docs/tipsandtricks/unix/...
扬-菲利普Gehrcke博士

8
以后如何恢复工作?我可以看到它正在使用ps -e运行。
Paulo Casaretto 2012年

26
disown,disown使进程成为守护程序之后,您看不到作业的输出,这意味着标准输入/输出被重定向到/ dev / null。因此,如果您打算my_job_command | tee my_job.log
放弃

8
有可能以某种方式做类似“ my_job_command | 发球my_job.log” 之后的命令已经启动?
2012年

23
disown从流程中取消所有管道的关联。要重新连接管道,请gdb按照此线程中的说明使用。更具体而言,这篇文章
mbrownnyc

185

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

kill -SIGSTOP PID 
kill -SIGCONT PID

SIGSTOP将暂停该过程并SIGCONT在后台继续该过程。因此,现在关闭两个终端都不会停止您的过程。


10
是的,这就是一个操作系统问题,在Windows上,Cygwin不能执行kill命令。
2013年

6
如果作业是从另一个ssh会话开始的,它也非常有用。
Amir Ali Akbari 2014年

5
只需记住disown %1在关闭它之前在第一个终端中执行即可。
2014年

1
这非常有用,因为我使用控制台启动了图形界面(在我的情况下kwin,崩溃后我从konsole开始,不考虑后果)。因此,如果我停止了kwin,一切都会冻结,并且我将无法运行bg
米歇尔2015年

@fred我没有这样做,它似乎仍在运行。可能还是我打错了PID?
没人

91

从外壳程序中分离正在运行的作业的命令(=使之成为nohup)是disown一个基本的外壳程序命令。

从bash-manpage(man bash):

放弃[-ar] [-h] [jobspec ...]

如果没有选项,则会从活动作业表中删除每个作业规范。如果给出了-h选项,则不会从表中删除每个jobspec,而是对其进行标记,以便在外壳程序收到SIGHUP时不将SIGHUP发送给该作业。如果不存在jobspec,并且-a和-r选项均未提供,则使用当前作业。如果未提供jobspec,则-a选项表示删除或标记所有作业;不带jobspec参数的-r选项将操作限制为正在运行的作业。除非jobspec没有指定有效的作业,否则返回值为0。

这意味着,一个简单的

disown -a

将从作业表中删除所有作业,并使它们不再工作


9
disown -a删除所有作业。简单disown仅删除当前作业。正如答案中的手册页所述。
2014年

73

这些是上面的好答案,我只想添加一个说明:

您不能disown是pid或流程,您不能disown是工作,那是重要的区别。

作业是连接到Shell的进程的概念,因此您必须将作业置于后台(而不是挂起),然后将其丢弃。

问题:

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

有关 Unix Job Control的详细讨论,请参见http://www.quantprinciple.com/invest/index.php/docs/tipsandtricks/unix/jobcontrol/


48

不幸的disown是特定于bash,并非在所有shell中都可用。

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

nohup -p pid

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


仅适用于AIXSolaris。“ AIX和Solaris版本的nohup具有-p选项,该选项修改正在运行的进程以忽略将来的SIGHUP信号。与上述bash内置的disown内置程序不同,nohup -p接受进程ID。” 消息来源
AlikElzin-kilaka,

27

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

如果成功,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,因为nohup会做,但这不是建议man open(2),因为可能的NFS问题。

如果我们得到-1作为返回值,则call perror("")输出错误消息。如果需要errno,请使用p errnogdb comand。

现在我们可以检查新重定向的文件了。/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>

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


确实非常有用,在简单情况下可能会很好地工作。但是请注意,更复杂的案例可能会惨败。我今天遇到了其中一个:我的进程修改了另一个执行输出的进程(大概是stderr),但是stdout已挂接到与其主机进行通信的过程。重定向主节点FD无效,因为该子节点继承了stderr,而关闭子节点的stdout会使正在管道另一端等待的主节点失败。X- | 尝试之前,请更好地了解您的流程。
cmaster-恢复莫妮卡2015年

@cmaster您可以检查是使用lsof(文件句柄的名称是pipe,而不是/dev/pts/1)还是通过ls -l /proc/<PID>/fd/<fd>(这显示了句柄的符号链接)重定向了句柄。同样,子流程仍然不能重定向输出,应该将其重定向到文件。
TrueY

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以退出shell,因为现在您可以进行操作了,因为该操作将在其自己的进程中在后台运行,因此它与shell无关。

这个过程相当于运行nohup SOMECOMMAND


3

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

nohup -p  processid>

这很好。即使关闭了终端窗口,它仍继续运行我的过程。我们将ksh作为默认shell,因此bgand disown命令不起作用。


2
  1. ctrl+ z -这将暂停作业(不会取消!)
  2. bg -这会将工作置于后台并在运行过程中返回
  3. disown -a -这将削减所有附件的工作量(因此您可以关闭终端,它仍然可以运行)

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

它不会继续nohup(根据我对您问题的理解,您在这里不需要它)。


我认为disown -a的行为是减少所有工作的依恋。但是,它不会关闭stdin / stdout管道,这意味着该进程仍将尝试从终端进行写入(/读取)
Kelthar

-2

在tcshell中,这在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
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.