1035

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

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

4

10 回答 10

1477

使用 bash 的Job Control将进程发送到后台:

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

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

kill -SIGSTOP PID 
kill -SIGCONT PID

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

于 2012-04-23T08:01:00.143 回答
100

将正在运行的作业与 shell 分开的命令(= 使其成为 nohup)是disown一个基本的 shell 命令。

从 bash 手册页(man bash):

拒绝 [-ar] [-h] [jobspec ...]

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

这意味着,一个简单的

disown -a

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

于 2009-03-09T08:38:41.417 回答
78

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

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

作业是附加到外壳的进程的概念,因此您必须将作业扔到后台(而不是挂起它),然后再拒绝它。

问题:

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

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

于 2009-11-19T15:48:01.557 回答
56

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

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

nohup -p pid

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

于 2013-03-16T23:49:15.940 回答
28

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* 文件处理程序(列)都说 'u' FD,即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

如果我们愿意,我们可以将 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>

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

于 2014-10-10T09:35:14.927 回答
11

简单和最简单的步骤

  1. Ctrl + Z---------->暂停进程
  2. bg -------------->恢复并运行后台
  3. disown %1------------->仅当您需要从终端分离时才需要
于 2020-08-26T18:18:41.070 回答
6

将运行进程发送到 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

于 2013-09-27T06:48:57.817 回答
4
  1. ctrl+ z - 这将暂停工作(不会取消!)
  2. bg- 这会将作业置于后台并在运行过程中返回
  3. disown -a- 这将切断所有带有作业的附件(因此您可以关闭终端,它仍然会运行)

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

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

于 2018-03-24T17:06:33.297 回答
3

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

nohup -p  processid>

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

于 2014-03-03T16:16:52.543 回答