我有一个进程已经运行了很长时间,不想结束它。
我如何把它放在nohup下(也就是说,即使我关闭终端,我如何使它继续运行?)
将正在运行的作业从shell中分离出来的命令是disown和一个基本的shell命令。
disown
从bash-manpage(man bash):
disown[-ar][-h][jobspec…] 如果没有选项,每个jobspec都会从活动作业表中删除。如果给出-h选项,则每个jobspec都不会从表中删除,但标记为如果shell收到SIGHUP,则不会将SIGHUP发送到作业。如果没有jobspec存在,并且既不提供-a也不提供-r选项,则使用当前作业。如果没有提供jobspec,则使用-a选项表示删除或标记所有作业;没有jobspec参数的-r选项将操作限制为正在运行的作业。返回值为0,除非jobspec没有指定有效的作业。
disown[-ar][-h][jobspec…]
如果没有选项,每个jobspec都会从活动作业表中删除。如果给出-h选项,则每个jobspec都不会从表中删除,但标记为如果shell收到SIGHUP,则不会将SIGHUP发送到作业。如果没有jobspec存在,并且既不提供-a也不提供-r选项,则使用当前作业。如果没有提供jobspec,则使用-a选项表示删除或标记所有作业;没有jobspec参数的-r选项将操作限制为正在运行的作业。返回值为0,除非jobspec没有指定有效的作业。
这意味着,一个简单的
disown -a
将从作业表中删除所有作业并使其成为nohup
使用bash的作业控制将进程发送到后台:
bg
disown -h [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)并运行:
ps
kill -SIGSTOP PIDkill -SIGCONT PID
SIGSTOP将暂停进程,SIGCONT将在后台恢复进程。所以现在,关闭两个终端不会停止您的进程。
SIGSTOP
SIGCONT
不幸的是,disown特定于bash,并不能在所有shell中使用。
某些风格的Unix(例如AIX和Solaris)在nohup命令本身上有一个选项,可以应用于正在运行的进程:
nohup
nohup -p pid
见http://en.wikipedia.org/wiki/Nohup
将正在运行的进程发送到nohup(http://en.wikipedia.org/wiki/Nohup)
nohup -p pid,它对我不起作用
然后我尝试了以下命令,效果非常好
运行一些人,/usr/bin/python /vol/scripts/python_scripts/retention_all_properties.py 1.
/usr/bin/python /vol/scripts/python_scripts/retention_all_properties.py 1
Ctrl+Z停止(暂停)程序并返回shell。
bg在后台运行它。
disown -h,以便在终端关闭时不会杀死进程。
disown -h
键入exit以退出shell,因为现在您可以开始了,因为操作将在其自己的进程中在后台运行,因此它不会被绑定到shell。
exit
这个过程相当于运行nohup SOMECOMMAND。
nohup SOMECOMMAND
在我的AIX系统上,我尝试过
nohup -p processid>
这工作得很好。即使在关闭终端窗口后,它仍继续运行我的进程。我们将ksh作为默认shell,因此bg和disown命令不起作用。
Node的答案真的很棒,但它留下了如何重定向stdout和stderr的问题。我在Unix&Linux上找到了一个解决方案,但它也不完整。我想合并这两个解决方案。这里是:
对于我的测试,我制作了一个名为loop.sh的小型bash脚本,它在无限循环中打印自身的pid,并在一分钟的睡眠中打印。
$./loop.sh
现在以某种方式获取此过程的PID。通常ps -C loop.sh足够好,但它在我的案例中被打印出来。
ps -C loop.sh
现在我们可以切换到另一个终端(或按^Z并在同一终端中)。现在gdb应该附加到此进程。
gdb
$ gdb -p <PID>
这将停止脚本(如果正在运行)。它的状态可以由ps -f <PID>检查,其中STAT字段是'T+'(或者在^Z'T'的情况下),这意味着(man ps(1))
ps -f <PID>
STAT
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。
open(path, O_TRUNC|O_CREAT|O_RDWR, S_IRUSR|S_IWUSR)
O_RDWR
O_WRONLY
/usr/sbin/lsof
FD
我检查了头文件 /usr/include/bits/fcntl.h值。
输出文件可以用O_APPEND打开,就像nohup所做的那样,但man open(2)不建议这样做,因为可能存在NFS问题。
O_APPEND
man open(2)
如果我们得到-1作为返回值,那么call perror("")会打印错误消息。如果我们需要errno,请使用p errno gdb comand。
call perror("")
p errno
现在我们可以检查新重定向的文件。/usr/sbin/lsof -p <PID>打印:
/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重定向到另一个文件。
call close(2)
call open(...)
现在附加的bash必须被释放,我们可以退出gdb:
bash
(gdb) detachDetaching from program: /bin/bash, process <PID>(gdb) q
如果脚本被gdb从另一个终端停止,它会继续运行。我们可以切换回loop.sh的终端。现在它不会在屏幕上写任何东西,而是运行并写入文件。我们必须把它放到后台。所以按^Z。
^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如下所示:
gdb -q -x loop.gdb -p <PID>
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>
我希望这是对解决方案的一个相当完整的描述。
这些简单的步骤将允许您在保持进程运行的同时关闭终端。
它不会放在nohup上(根据我对你问题的理解,你在这里不需要它)。
简单易行的步骤
Ctrl + Z
disown %1