linux后台执行

想退出secureCRT后,能够继续跑自己的进程

     为什么会有这样的需求?作为系统管理员,经常遇到这样的问题,用 telnet/ssh 登录了远程的 Linux 服务器,需要运行了一些耗时较长的任务,例如批量ping一些网段之类, 有时候却由于网络的不稳定导致任务中途失败,或者需要中途离开,总不会在等它结束吧,如果你退出SSH登陆的话,那么你的任务也会被终止了,岂不是白费精 力了?如何让命令或者任务在后台自己的运行,可以有很多方式实现,向大家都不陌生了,例如nohup,setsid和screen等等,我就简单说说吧。

    在我们通过SSH登陆服务器后,一般来说,所做的操作或者命令的输入都是属sshd下的shell的子进程,例如打开个SSH终端,输入ping www.163.com >>output.txt &,然后查看进程情况:
$ ps -ef|grep ping
sszheng 27491 27467 0 10:20 pts/0    00:00:00 ping www.163.com
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 
cdable_vars     off
cdspell         off
checkhash       off
checkwinsize    off
cmdhist         on
dotglob         off
execfail        off
expand_aliases on
extdebug        off
extglob         off
extquote        on
failglob        off
force_fignore   on
gnu_errfmt      off
histappend      off
histreedit      off
histverify      off
hostcomplete    on
huponexit       off
interactive_comments    on
lithist         off
login_shell     on
mailwarn        off
no_empty_cmd_completion off
nocaseglob      off
nocasematch     off
nullglob        off
progcomp        on
promptvars      on
restricted_shell        off
shift_verbose   off
sourcepath      on
xpg_echo        off
    上面的默认选项中,huponexit       off,这个情况时候,当你退出shell时候,后台的程序还会继续运行,但是这个是全局选项,有时候我们往往希望退出shell后,shell发起的进 程相应结束了,而不是一直运行,因为有时候你可能开了很多子进程,没有时间去一一关闭吧??往往这个选项是建议打开的。

huponexit打开后,所以后台进行的jobs,在shell退出后就会相应退出了,但是针对我们特定的任务时候,我们可以对它进行单独操作,可以有下面集中方法。
1、nohup
nohup的用途就是让提交的命令忽略 hangup 信号,使用方法:
$nohup ping www.163.com & 
如果没有重定向输入和输出的话,标准输出和标准错误缺省会被重定向到 nohup.out 文件中。一般像示例一样,加上"&"来将命令同时放入后台运行,也可用">filename 2>&1"来更改缺省的重定向文件名。退出shell后,ping会继续运行,直到命令执行结束。
$ ps -ef |grep ping       
sszheng   5377 5311 0 16:51 pts/1    00:00:00 ping www.163.com
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 www.163.com
sszheng   5389 5383 0 16:52 pts/0    00:00:00 grep ping


2、setsid

    nohup是通过忽略 HUP信号来使进程避免中途被中断,也可以用另一种方法,进程是不属于接受 HUP 信号的终端的shell子进程,那么自然也就不会受到 HUP 信号的影响了,真是白猫黑猫,抓到老鼠就是好猫,呵呵,废话多了。

    shell提供了setsid这个方法,

$setsid ping www.163.com & >>163.txt

$ ps -ef |grep ping

sszheng   5377     1 0 16:51 ?        00:00:00 ping www.163.com
sszheng   5395     1 0 16:56 ?        00:00:00 ping www.163.com
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 www.163.com &)

$ ps -ef |grep ping
sszheng   5377     1 0 16:51 ?        00:00:00 ping www.163.com
sszheng   5395     1 0 16:56 ?        00:00:00 ping www.163.com
sszheng   5401     1 0 17:03 pts/0    00:00:00 ping www.163.com
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进程对它们完成状态收集工作。

简要说一下screen,它也是后台执行的一个重要工具,只不过它的功能远远不止后台执行而已。
    Screen是一个可以在多个进程之间多路复用一个物理终端的窗口管理器。Screen中有会话的概念,用户可以在一个screen会话中创建多个 screen窗口,在每一个screen窗口中就像操作一个真实的telnet/SSH连接窗口那样。在screen中创建一个新的窗口有这样几种方式:

1.直接在命令行键入screen命令

$ screen

    Screen将创建一个执行shell的全屏窗口。你可以执行任意shell程序,就像在ssh窗口中那样。在该窗口中键入exit退出该窗口,如果这是该screen会话的唯一窗口,该screen会话退出,否则screen自动切换到前一个窗口。

2.Screen命令后跟你要执行的程序。

$ screen vi test.sh

Screen创建一个执行vi test.sh的单窗口会话,退出vi将退出该窗口/会话。

3.以上两种方式都创建新的screen会话。我们还可以在一个已有screen会话中创建新的窗口。在当前screen窗口中键入C-a c,即Ctrl键+a键,之后再按下c键,screen 在该会话内生成一个新的窗口并切换到该窗口。

具体用法就不说了,既然不属于ssh管理,那何来接受退出信号呢?请注意会话这个概念。

    有兴趣的童鞋们,还可以看看disown相关的东东,这个东东的需求是:如果事先在命令前加上 nohup 或者 setsid 就可以避免 HUP 信号的影响。但是如果我们未加任何处理就已经提交了命令,该如何补救才能让它避免 HUP 信号的影响呢? 
我们可以用如下方式来达成我们的目的。

  • disown -h jobspec 来使某个作业忽略HUP信号。
  • disown -ah 来使所有的作业都忽略HUP信号。
  • disown -rh 来使正在运行的作业忽略HUP信号。


上面的方式的对象是作业,如果我们在运行命令时在结尾加了"&"来使它成为一个作业并在后台运行,我们可以通过jobs命令来得到所有作业的列表。但是如果并没有把当前命令作为作业来运行,如何才能得到它的作业号呢?答案就是用 CTRL-z(按住Ctrl键的同时按住z键)了!

CTRL-z 的用途就是将当前进程挂起(Suspend),然后我们就可以用jobs命令来查询它的作业号,再用bg jobspec来将它放入后台并继续运行。需要注意的是,如果挂起会影响当前进程的运行结果,就不推荐大家使用了。

 

就说到这了,说错了,请指点。

posted @ 2011-10-31 15:19  熊健  阅读(19665)  评论(6编辑  收藏  举报