我有一个已经运行了很长时间的进程,不想结束它。
我如何把它放在nohup下(也就是说,我如何使它继续运行,即使我关闭了终端?)
我有一个已经运行了很长时间的进程,不想结束它。
我如何把它放在nohup下(也就是说,我如何使它继续运行,即使我关闭了终端?)
将正在运行的作业从shell中分离(=使其成为nohup)的命令是disown,是一个基本的shell命令。
来自bash-manpage (man bash):
disown [-ar] [-h] [jobspec ...] Without options, each jobspec is removed from the table of active jobs. If the -h option is given, each jobspec is not removed from the table, but is marked so that SIGHUP is not sent to the job if the shell receives a SIGHUP. If no jobspec is present, and neither the -a nor the -r option is supplied, the current job is used. If no jobspec is supplied, the -a option means to remove or mark all jobs; the -r option without a jobspec argument restricts operation to running jobs. The return value is 0 unless a jobspec does not specify a valid job.
这意味着,这是一个简单的
disown -a
将从工作表中删除所有的工作并使它们nohup
使用bash的Job Control将进程发送到后台:
按Ctrl+Z停止(暂停)程序并返回shell。 Bg在后台运行它。 Disown -h [job-spec],其中[job-spec]是作业号(例如%1是第一个运行的作业;使用jobs命令查找您的号码),这样当终端关闭时作业就不会被终止。
上面这些都是很好的答案,我只是想澄清一下:
你不能否认一个pid或进程,你不能否认一个工作,这是一个重要的区别。
作业是附加到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 PID
kill -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,它对我不起作用
然后我尝试了下面的命令,它工作得很好
运行some somcommand, 输入/usr/bin/python /vol/scripts/python_scripts/retention_all_properties.py。 按Ctrl+Z停止(暂停)程序并返回shell。 Bg在后台运行它。 否认-h,这样当终端关闭时进程不会被终止。 输入exit退出shell,因为现在你已经准备好了,因为操作将在后台自己的进程中运行,所以它没有绑定到shell。
这个过程相当于运行nohup somcommand。
在我的AIX系统上,我尝试了一下
nohup -p processid>
这很有效。它继续运行我的进程,即使关闭终端窗口。我们有ksh作为默认shell,所以bg和disown命令不起作用。
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)成功返回0。
(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_RDWR O_WRONLY可以应用,但/usr/sbin/lsof说'u'对于所有std*文件处理程序(FD列),这是O_RDWR。
我检查了头文件/usr/include/bits/fcntl.h中的值。
可以使用O_APPEND打开输出文件,就像nohup所做的那样,但是man open(2)不建议这样做,因为可能存在NFS问题。
如果返回值为-1,则调用perror("")打印错误消息。如果我们需要errno,使用p errno gdb命令。
现在我们可以检查新重定向的文件。/usr/sbin/lsof -p <PID>打印
loop.sh <PID> truey 1u REG 0,26 0 15008411 /home/truey/loop.out
如果我们愿意,我们可以将stderr重定向到另一个文件,如果我们想使用调用close(2)并再次使用不同的文件名调用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
现在我们可以退出这场舞会了。进程继续在后台运行。如果我们退出它的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>。我的循环。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>
我希望这是对解决方案相当完整的描述。
CTRL + z -暂停作业(不会取消!) Bg -这将把作业放在后台,并在运行过程中返回 Disown -a -这将切断与job的所有附件(所以你可以关闭终端,它仍然会运行)
这些简单的步骤将允许您在保持进程运行的同时关闭终端。
它不会放nohup(基于我对你的问题的理解,你不需要它)。
简单简单的步骤
Ctrl + Z ---------->暂停进程 bg -------------->恢复并运行后台 只有当您需要从终端分离时才需要否认%1 ------------->