要想程序在后台稳定运行,先要关闭或者重定向其标准输出,然后需要先解决两个问题:
ctrl+c, ctrl+z
不能终止程序。- 关闭命令行终端后,默认会向此终端启动的所有程序发生
SIGHUP
信号,导致程序被终止。
解决第一个问题,我们只需要在程序后面加上&
即可。
在解决第二个问题之前,我们先看看终端连接。
终端连接
我们xshell这样的工具连接上服务器,其实就是建立ssh连接,默认是22端口,每一个连接就是一个进程,我在一个终端启动了一个进程main60
,然后在另一个终端执行如下命令
$ ps -ef | grep main60
vagrant 13890 13865 0 09:19 pts/0 00:00:00 ./main60
vagrant 13932 13910 0 09:19 pts/1 00:00:00 grep --color=auto main60
第一行输出,13890 为 main60 的进程ID,13865 为其父进程ID,pts/0 为终端编号默认从0开始。
第二行输出,13932 为 grep 程序的进程ID,13910 为其父进程ID,pts/1 为终端编号。
那么它们的父进程是什么呢?
$ ps -ef | grep 13865
vagrant 13865 13851 0 09:12 pts/0 00:00:00 -bash
vagrant 13890 13865 0 09:19 pts/0 00:00:00 ./main60
vagrant 13937 13910 0 09:33 pts/1 00:00:00 grep --color=auto 13865
其实就是ssh连接。
你通过终端启动的进程,它们的父进程或者更上级的进程就是连接进程。
当你关闭终端的时候,ssh服务就能检测到,它在退出连接进程之前会先找到所有的子进程,向它们发生SIGHUP信号,如果你的进程没有捕获此信号,那么就会终止。
我将启动方式由./main60
改成./main60 &
,虽然看起来程序在后台运行了,但是当我关闭 pts/0 这个终端的时候,程序都退出了。
那么解决方式就是捕获 SIGHUP 信号;或者和它断绝父子关系。一般会选择后者。
断绝父子关系也很简单,那就是让 main60 fork 出一个子进程,然后父进程退出,这样子进程就会被 PID=1 的进程接管。
修改了 main60 程序,增加了 fork 子进程,再次运行。
$ ps -ef | grep main60
vagrant 14077 1 0 10:19 pts/0 00:00:00 ./main60
vagrant 14081 13910 0 10:20 pts/1 00:00:00 grep --color=auto main60
可见父进程以及变为1,但是还是有 pts/0 的标记,会有影响吗?
我关闭了 pts/0 之后
$ ps -ef |grep main60
vagrant 14077 1 0 10:19 ? 00:00:00 ./main60
vagrant 14084 13910 0 10:22 pts/1 00:00:00 grep --color=auto main60
这样看着就完美了,程序也没有退出。
其实使用这种方式就同时解决了上面的两个问题了。连&
符都不需要加,非常推荐。
nohup命令简介
nohup 命令的作用可以将程序以忽略挂起信号(SIGHUP)的方式运行。常见的用法是和 & 命令一同使用,将命令放置到后台运行,即使终端关掉了,进程会忽略挂起信号,继续运行。
nohup官网地址: http://www.gnu.org/software/coreutils/manual/html_node/nohup-invocation.html
官网的简单介绍:
nohup runs the given command with hangup signals ignored, so that the command can continue running in the background after you log out.
注意:
1,如果使用 nohup 执行程序未显示进行标准输出重定向,则标准输出默认重定向当前工作目录的 nohup.out
文件中。如果当前工作目录的 nohup.out
文件不可写,输出重定向到 $HOME/nohup.out
文件中。如果没有文件能创建或打开用于追加,那么 command 参数指定的命令不可调用。
2,如果标准错误未显示重定向,那么标准错误默认重定向到与标准输出相同的文件。
命令格式
nohup COMMAND [ARGS]
nohup OPTION
3选项说明
--help
显示帮助信息并退出
--version
显示版本信息并退出
常用示例
$ nohup ./main60
nohup: 忽略输入并把输出追加到"nohup.out"
$ ps -ef | grep main60
vagrant 14148 14124 0 10:55 pts/0 00:00:00 ./main60
$ ps -ef | grep 14124
vagrant 14124 14110 0 10:52 pts/0 00:00:00 -bash
vagrant 14148 14124 0 10:55 pts/0 00:00:00 ./main60
可见 nohup 的实现原理并不是创建子进程,而是直接将main60
替换了自己的进程空间,然后捕获 SIGHUP 信号,然后再启动进程。
2,标准输出与标准错误输出重定向。
nohup ./main60 > test.log 2>&1 &
nohup ./main60 > /dev/null 2>&1 &
3,指定输出文件, 输出被重定向到 output.txt 文件中
nohup bash a.sh &> error.txt
注意:
1,2>&1
标识标准错误输出重定向等同于标准输出重定向,即标准错误输出也重定向到文件 test.log;
2,&
命令是命令放在后台执行,需要放在命令的最后面。