From Andy at SuZhou sklcc.com
我们经常会遇到这么一种情况:ssh/telnet到远程的一台主机,然后执行了一个需要长时间运行的程序,但是由于网络原因导致连接不稳定,在当连接断了之后,我们在远端主机上运行的这个程序也会被终止。这时我们就希望能把它转至后台运行,并且当客户端失去连接之后也不会中断程序。
一般后台运行
要让一个程序在后台运行有好几种方法,首先就是ctrl+z
,使用ctrl+z
会让程序暂时挂起在后台,然后可以看到系统提示:
[1]+ Stopped /root/bin/rsync.sh
其中’[1]‘是后台作业号,我们可以通过使用bg
命令来让它在后台运行:bg 1 # bg + 后台作业号
,然后我们可以通过jobs
命令来查看所有后台程序的运行状态
jobs
[1]+ Running /root/bin/rsync.sh &
如果想把它调回前台可以使用fg 1
,当然这样之后就只能在控制台中等待这个程序运行结束。
总结一下就是:
ctrl+z 把程序挂起在后台(此时为挂起状态,在后台但是不会继续运行)
bg %jobnumber 把任务在后台运行起来
fg %jobnumber 把任务转到前台运行
jobs 查看当前后台所有的任务的状态
& 在命令之后加上这个符号表示让此命令运行在后台(但是命令的输出还是会从标准输出显示,也就是会出现在控制台)
客户端失连之后程序退出的原因
上面提到的方法只是能够让程序在后台运行,但是当客户端失去连接之后程序还是会被终止,原因是由于用以上方法在后台执行程序,程序的父进程还是当前终端的进程,所以当当前终端退出的时候(也就是客户端失去连接的时候),也就意味着程序的父进程退出了,此时系统会发送hangup
型号给所有的子进程,子进程收到此消息之后也会退出程序,所以如果我们希望程序在客户端失去连接之后仍然能运行的话,那么只有两种方法:
- 让程序忽略
hangup
信号- 让程序的父进程是init进程,而不是当前终端的进程
解决方案
忽略hangup信号
使用nohup
命令可以实现让命令忽略hangup信号,在它的man-page中也有说明:
nohup - run a command immune to hangups, with output to a non-tty
用法也很简单,只需要在原来的命令前面加上nohup就行了,例如:nohup ./test &
如果手动重定向标准输出的话,nohup命令会自动把命令的标准输出重定向到当前目录的nohup.out文件中
BTW,在重定向输出的时候,1表示标准输出,2表示错误输出,0表示标准输入,如果需要重定向一个程序的标准输出的话只需要./test 1>test.out &
即可,如果需要让一个程序在后台运行并且不会有任何输出到终端的话,需要把错误输出也重定向,即./test 1>test.log 2>test.err &
,如果不需要记录命令的输出信息的话,可以重定向到/dev/null
文件,这是linux中的一个黑洞文件,任何输出到这个文件的信息都会被吞噬,即./test &>/dev/null &
,这条命令也等于./test 1>/dev/null 2>&1
,现在后者见的比较多,前者我在baidu和bing中都没怎么搜的到,但我记得是可以的。在后者中,先是把标准输出重定向到黑洞设备,然后把错误输出重定向到标准输出,这样所有输出都会被吃掉了。
父进程为init
使用setsid
命令就可以让命令的父进程为init,在它的man-page的说明是:
setsid - run a program in a new session
至于它的使用方法也很简单,和nohup
一样,只要在原来的命令之前加上setsid
即可,例如:
1 2 3 4 |
|
另外还有一个方法也可以实现同样的效果,就是加括号,例如(./test &)
。除了以上提到的3种方法之外,还有一种方法就是写成service,关于如何写service,在下篇博客会进行介绍。
总结一下:
nohup 让程序忽略hangup信号从而让程序可以继续运行
setsid 让程序在一个新的session中运行,所以父进程就不会是当前终端
(shell) 与setsid一样的效果