linux进程后台运行
在linux上启动Web服务,当退出终端后,Web服务进程也会随着关闭。产生这种问题的原因在于,当用户注销或者网络断开后,终端后收到挂断信号(SIGHUP),并向子进程广播SIGHUP信号,子进程收到SIGHUP信号而关闭。因此,让linux后台持续运行的方法有以下几种:
1.改变子进程的所属的父进程,只要父进程不关闭,子进程也不会关闭;
2.让子进程忽略挂断信号,即使收到SIGHUP信号,也任性地继续运行;
3.不向子进程广播SIGHUP信号,子进程收不到SIGHUP信号,因而不会关闭。
第一种方式
使用setsid
可以新开一个session运行进程,此session不从属于当前终端,因此终端关闭时进程也不会退出。
1 | >setsid ping www.baidu.com |
从上面可以看出,ping进程的父进程是1,即init进程,因此只要电脑不关机,ping进程就不会停止。
linux下自带setsid
这个命令,但是macOS上并没有这个命令。此时,可以结合使用()
和&
达到同样的效果。()
可以新开一个subshell,&
让命令后台运行。
1 | >(ping www.baidu.com &) |
可以看到,效果与setsid
是一样的。
第二种方式
使用nohup
可以使进程忽略SIGHUP信号,这种方式也是最常用的。例如:
1 | >nohup ping www.baidu.com & |
可以看到,ping进程的父进程并不为1,nohup是让进程忽略SIGHUP信号实现进程不退出的。
需要注意的是,当在zsh
中使用nohup
时,退出终端时会提示:
1 | zsh: you have running jobs. |
再次强行退出,那么进程仍然会被干掉。这时候,采用以下命令:
1 | nohup ping www.baidu.com &! |
第三种方式
使用nohup的前提是,进程以nohup来启动。但是,如果启动时忘记了以nohup启动,有什么方法在不停止进程的情况,让它继续后台运行呢?接下来就要将另外一个命令:disown
。disown
的原理是,将子进程从终端任务队列中移除,所以即使终端挂断,子进程也收不到SIGHUP信号。
假设现在使用ping命令:
1 | >ping www.baidu.com |
这时采用Ctrl + z
使它进入后台,使用jobs
查看后台进程:
1 | >jobs |
可以看到虽然ping进程进入后台,但是进程被挂起了,没有继续运行。使用bg
命令可以使他在后台继续运行:
1 | >bg %1 |
通过组合Ctrl + z
和bg
,成功地将前台进程变为了后台进程。为了让进程不随终端关闭而终止,还差最后一步:
1 | >disown %1 |
上面使用jobs
命令查看任务队列,发现ping进程不在任务队列中,意味着进程不会收到SIGHUP信号。
注意事项
以上我们通过三种方式,避免进程随着终端关闭而被杀掉:
setsid
改变父进程,只要父进程不关闭,进程就可以持续运行;nohup
使得进程忽略SIGHUP信号,父进程即使发送挂断信号,进程也不会终止;disown
将进程从任务队列中移除,保证进程收不到SIGHUP信号。
但是,以上种种方法只是避免了进程受到SIGHUP信号的影响,进程的持续运行还需要一些其他环境,例如stdin、stdout以及stderr。通常从终端启动的进程,会继承终端的stdin、stdout和stderr。当终端断掉之后,stdin、stdout和stderr也会随着消失,若此时后台进程需要读写stdin、stdout、stderr,该进程将会暂停或者挂住。所以,为保证进程正常后台运行,最好启动时对输入输出重定向:
1 | >ping www.baidu.com > a.log 2>&1 & |
此时,将stdout和stderr重定向到文件a.log
中,文件a.log
不受终端关闭的影响。如果进程依赖于stdin,意思是进程需要由于键盘输入,那就说明这是个交互式程序,交互式程序后台运行就没多大意义了。
参考链接
Linux 技巧:让进程在后台可靠运行的几种方法
Difference between nohup, disown and &
Author: jingsam
Link: https://jingsam.github.io/2018/05/07/linux-nohup.html
License: 知识共享署名-非商业性使用 4.0 国际许可协议