我有一个已经运行了很长时间并且不想结束的进程。
我该如何将它放在nohup下(也就是说,如果我关闭终端,它仍然可以继续运行)?
我有一个已经运行了很长时间并且不想结束的进程。
我该如何将它放在nohup下(也就是说,如果我关闭终端,它仍然可以继续运行)?
使用bash的作业控制(Job Control)将进程发送到后台:
bg
在后台运行程序。disown -h [job-spec]
其中[job-spec]是作业号(如第一个运行的作业为%1
,可以用jobs
命令查看),以便关闭终端时不会杀死该作业。disown -h
可能是更准确的答案:“使disown的行为更像nohup(即作业将留在当前shell进程树中,直到您退出shell),这样您就可以看到此shell启动的所有作业。”(来自[http://www.quantprinciple.com/invest/index.php/docs/tipsandtricks/unix/jobcontrol/]) - Dr. Jan-Philip Gehrckedisown
命令后,你将无法查看作业的输出。disown
命令会将进程变为守护进程,这意味着标准输入/输出会被重定向到 /dev/null
。因此,如果你计划使用 disown
命令来处理作业,最好在启动作业时将其日志记录到文件中,例如:my_job_command | tee my_job.log
。 - rustyxps
命令),并运行以下命令:kill -SIGSTOP PID
kill -SIGCONT PID
SIGSTOP
命令将暂停进程,SIGCONT
命令将在后台恢复进程。这意味着现在,关闭你的两个终端不会停止你的进程。
disown %1
即可。 - fredkwin
启动了一个崩溃后没有考虑后果)。因此,如果我停止 kwin,一切都会冻结,我没有运行 bg
的可能性! - Michelekill -SIGTSTP PID
和 kill -SIGCONT PID
。 - Pablo Bianchi将正在运行的作业与shell分离(即使其成为nohup)的命令是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。
disown -a
命令会移除所有作业。而简单的 disown
命令只会移除当前作业。正如答案中所述的手册页面。 - Rune Schjellerup Philosof这些是很好的答案,我只想添加一个澄清:
你不能disown
一个pid或进程,你需要disown
一个job,这是一个重要的区别。
一个job是一个附加到shell的进程的概念,因此您必须将作业放入后台(而不是暂停它),然后disown它。
问题:
% jobs
[1] running java
[2] suspended vi
% disown %1
请到http://www.quantprinciple.com/invest/index.php/docs/tipsandtricks/unix/jobcontrol/了解更详细的Unix作业控制讨论。
遗憾的是,disown
命令只适用于 bash 而不是所有的 shell。
某些 Unix 版本(例如 AIX 和 Solaris)在 nohup
命令本身上有一个选项,可以应用于正在运行的进程:
nohup -p pid
AIX
和 Solaris
。 "Nohup 的 AIX 和 Solaris 版本具有 -p
选项,该选项修改正在运行的进程以忽略未来的 SIGHUP 信号。与 bash 中上述描述的 disown 内置不同,nohup -p 接受进程 ID。"。来源 - AlikElzin-kilaka为了进行测试,我编写了一个名为loop.sh的小型bash脚本,在无限循环中打印自己的pid,并休眠一分钟。
$./loop.sh
ps -C loop.sh
就足够了,但在我的情况下会打印出来。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等同于open(path, O_TRUNC|O_CREAT|O_RDWR, S_IRUSR|S_IWUSR)
。可以使用O_WRONLY
代替O_RDWR
,但是/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命令。
现在我们可以检查新重定向的文件。/usr/sbin/lsof -p <PID>
会打印:
loop.sh <PID> truey 1u REG 0,26 0 15008411 /home/truey/loop.out
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)
评论
可以通过创建一个包含命令的文件(例如loop.gdb)来自动化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>
lsof
(文件句柄的名称为 pipe
,而不是像 /dev/pts/1
)或者 ls -l /proc/<PID>/fd/<fd>
来检查句柄是否被重定向。此外,子进程仍然可能有未重定向的输出,这些输出应该被重定向到一个文件中。 - TrueY简单易行的步骤
Ctrl + Z
----------> 挂起进程bg
--------------> 恢复并在后台运行disown %1
-------------> 仅在需要从终端分离时使用disown -h %1
似乎可以避免 SIGHUP(完全将进程与终端分离)。 - Fernando Fabreti将正在运行的进程发送到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 暂停程序并返回到shell。
bg
在后台运行。
disown -h
避免在关闭终端时终止该进程。
输入exit
退出shell,因为现在你可以自由地进行操作了,该操作将在后台自己运行,因此它不会与shell绑定。
该过程等同于运行nohup SOMECOMMAND
。
bg
- 这将把任务放在后台运行并返回。disown -a
- 这将切断与任务的所有联系(因此您可以关闭终端,它仍将运行)这些简单的步骤将使您能够关闭终端而保持进程正在运行。
它不会使用nohup
(根据我对您问题的理解,您在这里不需要它)。
nohup -p processid>
这个方法很有效。即使关闭终端窗口,它也可以继续运行我的进程。由于我们的默认shell是ksh,因此bg
和disown
命令无法使用。
yourExecutable &
,输出持续出现在屏幕上,而且Ctrl+C
似乎无法停止任何东西,只需盲目地键入disown;
并按下Enter
,即使屏幕正在滚动输出,你也看不到你正在输入什么。该进程将被取消关联,并且您可以关闭终端而不使该进程终止。 - Nav