注册 登录  
 加关注
   显示下一条  |  关闭
温馨提示!由于新浪微博认证机制调整,您的新浪微博帐号绑定已过期,请重新绑定!立即重新绑定新浪微博》  |  关闭

云之南

风声,雨声,读书声,声声入耳;家事,国事,天下事,事事关心

 
 
 

日志

 
 
关于我

专业背景:计算机科学 研究方向与兴趣: JavaEE-Web软件开发, 生物信息学, 数据挖掘与机器学习, 智能信息系统 目前工作: 基因组, 转录组, NGS高通量数据分析, 生物数据挖掘, 植物系统发育和比较进化基因组学

网易考拉推荐

linux后台执行  

2012-03-29 16:10:25|  分类: linux&shell |  标签: |举报 |字号 订阅

  下载LOFTER 我的照片书  |

http://www.cnblogs.com/SuperXJ/archive/2011/10/31/2230314.html

http://www.ibm.com/developerworks/cn/linux/l-cn-nohup/

想退出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来将它放入后台并继续运行。需要注意的是,如果挂起会影响当前进程的运行结果,就不推荐大家使用了。

 

  linux下杀死进程(kill)的N种方法

常规篇:

 首先,用ps查看进程,方法如下:

$ ps -ef

……
smx       1822     1  0 11:38 ?        00:00:49 gnome-terminal
smx       1823  1822  0 11:38 ?        00:00:00 gnome-pty-helper
smx       1824  1822  0 11:38 pts/0    00:00:02 bash
smx       1827     1  4 11:38 ?        00:26:28 /usr/lib/firefox-3.6.18/firefox-bin
smx       1857  1822  0 11:38 pts/1    00:00:00 bash
smx       1880  1619  0 11:38 ?        00:00:00 update-notifier
……
smx      11946  1824  0 21:41 pts/0    00:00:00 ps -ef

或者:

$ ps -aux

……

smx       1822  0.1  0.8  58484 18152 ?        Sl   11:38   0:49 gnome-terminal
smx       1823  0.0  0.0   1988   712 ?        S    11:38   0:00 gnome-pty-helper
smx       1824  0.0  0.1   6820  3776 pts/0    Ss   11:38   0:02 bash
smx       1827  4.3  5.8 398196 119568 ?       Sl   11:38  26:13 /usr/lib/firefox-3.6.18/firefox-bin
smx       1857  0.0  0.1   6688  3644 pts/1    Ss   11:38   0:00 bash
smx       1880  0.0  0.6  41536 12620 ?        S    11:38   0:00 update-notifier
……
smx      11953  0.0  0.0   2716  1064 pts/0    R+   21:42   0:00 ps -aux


ps -u username 查看用户的进程

此时如果我想杀了火狐的进程就在终端输入:

$ kill -s 9 1827

其中-s 9 制定了传递给进程的信号是9,即强制、尽快终止进程。各个终止信号及其作用见附录。

1827则是上面ps查到的火狐的PID。

简单吧,但有个问题,进程少了则无所谓,进程多了,就会觉得痛苦了,无论是ps -ef 还是ps -aux,每次都要在一大串进程信息里面查找到要杀的进程,看的眼都花了。

进阶篇:

改进1:

把ps的查询结果通过管道给grep查找包含特定字符串的进程。管道符“|”用来隔开两个命令,管道符左边命令的输出会作为管道符右边命令的输入。

$ ps -ef | grep firefox
smx       1827     1  4 11:38 ?        00:27:33 /usr/lib/firefox-3.6.18/firefox-bin
smx      12029  1824  0 21:54 pts/0    00:00:00 grep --color=auto firefox

这次就清爽了。然后就是

$kill -s 9 1827

还是嫌打字多?

改进2——使用pgrep:

一看到pgrep首先会想到什么?没错,grep!pgrep的p表明了这个命令是专门用于进程查询的grep。

$ pgrep firefox
1827

看到了什么?没错火狐的PID,接下来又要打字了:

$kill -s 9 1827

改进3——使用pidof:

看到pidof想到啥?没错pid of xx,字面翻译过来就是 xx的PID。

$ pidof firefox-bin
1827
和pgrep相比稍显不足的是,pidof必须给出进程的全名。然后就是老生常谈:

$kill -s 9 1827

无论使用ps 然后慢慢查找进程PID 还是用grep查找包含相应字符串的进程,亦或者用pgrep直接查找包含相应字符串的进程PID,然后手动输入给kill杀掉,都稍显麻烦。有没有更方便的方法?有!

改进4:

$ps -ef | grep firefox | grep -v grep | cut -c 9-15 | xargs kill -s 9

说明:

“grep firefox”的输出结果是,所有含有关键字“firefox”的进程。

“grep -v grep”是在列出的进程中去除含有关键字“grep”的进程。

“cut -c 9-15”是截取输入行的第9个字符到第15个字符,而这正好是进程号PID。

“xargs kill -s 9”中的xargs命令是用来把前面命令的输出结果(PID)作为“kill -s 9”命令的参数,并执行该命令。“kill -s 9”会强行杀掉指定进程。

难道你不想抱怨点什么?没错太长了

改进5:

知道pgrep和pidof两个命令,干嘛还要打那么长一串!

$ pgrep firefox | xargs kill -s 9

改进6:

$ ps -ef | grep firefox | awk '{print $2}' | xargs kill -9
kill: No such process

有一个比较郁闷的地方,进程已经正确找到并且终止了,但是执行完却提示找不到进程。

其中awk '{print $2}' 的作用就是打印(print)出第二列的内容。根据常规篇,可以知道ps输出的第二列正好是PID。就把进程相应的PID通过xargs传递给kill作参数,杀掉对应的进程。

改进7:

难道每次都要调用xargs把PID传递给kill?答案是否定的:

$kill -s 9 `ps -aux | grep firefox | awk '{print $2}'`

改进8:

没错,命令依然有点长,换成pgrep。

$kill -s 9 `pgrep firefox`

改进9——pkill:

看到pkill想到了什么?没错pgrep和kill!pkill=pgrep+kill。

$pkill -9 firefox

说明:"-9" 即发送的信号是9,pkill与kill在这点的差别是:pkill无须 “s”,终止信号等级直接跟在 “-“ 后面。之前我一直以为是 "-s 9",结果每次运行都无法终止进程。

改进10——killall:

killall和pkill是相似的,不过如果给出的进程名不完整,killall会报错。pkill或者pgrep只要给出进程名的一部分就可以终止进程。

$killall -9 firefox



 

  评论这张
 
阅读(945)| 评论(0)
推荐 转载

历史上的今天

在LOFTER的更多文章

评论

<#--最新日志,群博日志--> <#--推荐日志--> <#--引用记录--> <#--博主推荐--> <#--随机阅读--> <#--首页推荐--> <#--历史上的今天--> <#--被推荐日志--> <#--上一篇,下一篇--> <#-- 热度 --> <#-- 网易新闻广告 --> <#--右边模块结构--> <#--评论模块结构--> <#--引用模块结构--> <#--博主发起的投票-->
 
 
 
 
 
 
 
 
 
 
 
 
 
 

页脚

网易公司版权所有 ©1997-2016