想退出secureCRT后,能够继续跑自己的进程
为什么会有这样的需求?作为系统管理员,经常遇到这样的问题,用 telnet/ssh 登录了远程的 Linux 服务器,需要运行了一些耗时较长的任务,例如批量ping一些网段之类, 有时候却由于网络的不稳定导致任务中途失败,或者需要中途离开,总不会在等它结束吧,如果你退出SSH登陆的话,那么你的任务也会被终止了,岂不是白费精 力了?如何让命令或者任务在后台自己的运行,可以有很多方式实现,向大家都不陌生了,例如nohup,setsid和screen等等,我就简单说说吧。
在我们通过SSH登陆服务器后,一般来说,所做的操作或者命令的输入都是属sshd下的shell的子进程,例如打开个SSH终端,输入ping >>output.txt &,然后查看进程情况:
$ ps -ef|grep ping
sszheng 27491 27467 0 10:20 pts/0 00:00:00 ping
sszheng 27535 27467 0 11:40 pts/0 00:00:00 grep ping
很显然它是shell的子进程,命令由一个子shell在后台执行,当前shell(27467)立即取得控制等候用户输入,所以我的grep就可以使用了。后台命令和当前shell的执行是并行的,他们没有互相的依赖、等待关系,所以是异步的并行。 现在问题来了,如果ssh退出了,bash结束了,那么这个工作过程如何呢?后台执行的能否继续下去?
这里涉及到两个问题,就是退出ssh后,在我们exit执行的shell时候,会不会向我们后台的jobs发送SIGHUP信号呢?
如果发送了SIGHUP信号,那么所有该shell下运行的进程都会被终止,也就是所希望的后台执行没有实现。在shell的options中,有huponexit这个选项,意思就是退出shell时候,是否发送这个SIGHUP信号?
$ shopt
…… ……… …… ………… ……… ……… …… ………
huponexit off
…… ……… ………… …………… ……… ……… ……
上面的默认选项中,huponexit off,这个情况时候,当你退出shell时候,后台的程序还会继续运行,但是这个是全局选项,有时候我们往往希望退出shell后,shell发起的进 程相应结束了,而不是一直运行,因为有时候你可能开了很多子进程,没有时间去一一关闭吧??往往这个选项是建议打开的。
huponexit打开后,所以后台进行的jobs,在shell退出后就会相应退出了,但是针对我们特定的任务时候,我们可以对它进行单独操作,可以有下面集中方法。
1、nohup
nohup的用途就是让提交的命令忽略 hangup 信号,使用方法:
$nohup ping &
如果没有重定向输入和输出的话,标准输出和标准错误缺省会被重定向到 nohup.out 文件中。一般像示例一样,加上"&"来将命令同时放入后台运行,也可用">filename 2>&1"来更改缺省的重定向文件名。退出shell后,ping会继续运行,直到命令执行结束。
$ ps -ef |grep ping
sszheng 5377 5311 0 16:51 pts/1 00:00:00 ping
sszheng 5379 5311 0 16:51 pts/1 00:00:00 grep ping
退出shell后,重新登陆查看,ping进程依然在执行,只不过他的PPID变成了1,也就是被init所管理的孤儿进程了,稍后说一下孤儿进程。
$ ps -ef |grep ping
sszheng 5377 1 0 16:51 ? 00:00:00 ping
sszheng 5389 5383 0 16:52 pts/0 00:00:00 grep ping
2、setsid
nohup是通过忽略 HUP信号来使进程避免中途被中断,也可以用另一种方法,进程是不属于接受 HUP 信号的终端的shell子进程,那么自然也就不会受到 HUP 信号的影响了,真是白猫黑猫,抓到老鼠就是好猫,呵呵,废话多了。
shell提供了setsid这个方法,
$setsid ping & >>163.txt
$ ps -ef |grep ping
sszheng 5377 1 0 16:51 ? 00:00:00 ping
sszheng 5395 1 0 16:56 ? 00:00:00 ping
sszheng 5397 5383 0 16:57 pts/0 00:00:00 grep ping
大家应该注意到,上一个示例中,ping的父进程是5311,当它的父进程退出后,它才被init(PID=1)收养,而setsid直接把ping(pid=5395)给init了,那么就无所谓的shell退出影响了。
3、(&)
再提一下关于subshell的使用,我们知道,将一个或多个命名包含在“()”中就能让这些命令在子 shell 中运行中,当我们将"&"也放入“()”内之后,我们就会发现所提交的作业并不在作业列表中,也就是说,是无法通过jobs来查看的。看看下面的进程id就知道了:
$(ping &)
$ ps -ef |grep ping
sszheng 5377 1 0 16:51 ? 00:00:00 ping
sszheng 5395 1 0 16:56 ? 00:00:00 ping
sszheng 5401 1 0 17:03 pts/0 00:00:00 ping
sszheng 5403 5383 0 17:03 pts/0 00:00:00 grep ping
可以看到,执行的5401的父进程是init了,这样子也可以达到忽略hup信号的目的了。
说到这里,相信大家都略明白后台执行的方法了,简单说下原理:bash进程终止后,init 进程会接管父进程留下的这些“孤儿进程”,所以PPID是1了,孤儿进程不是僵尸进程,下面是他们的概念和区别
僵尸进程:一个子进程在其父进程还没有调用wait()或waitpid()的情况下退出。这个子进程就是僵尸进程。
孤儿进程:一个父进程退出,而它的一个或多个子进程还在运行,那么那些子进程将成为孤儿进程。孤儿进程将被init进程(进程号为1)所收养,并由init进程对它们完成状态收集工作。
阅读(2586) | 评论(2) | 转发(3) |