Linux任务的高级管理:程序后台运行及控制

下操作,不可避免的需要让程序运行在后台而不妨碍前台的操作。在Linux有个概念称之为Job Control,由于Bash下的运行的任何程序都是当前Bash下的子程序,而job control也即管理当前Bash下的子程序。所以,Job Control的概念是不能跨Bash管理,比如我们不能在tty1中管理tty2中的程序。

其中我们在Bash中最常用的应该就是&符了,这个符号跟在要运行的程序的后面,像下面这样:

ping blog.useasp.net &

这样配置后,我们将会发现,运行后,系统返回的是类似下面这样的:

[1] 23911

这样我们就将这个ping放到了当前Bash的后台进行运行,我们此时仍可以正常的在Bash下进行其他的操作。但是你也许会发现这种方式运行的程序虽然不影响你当前操作,但是运行的输出却总是和我们抢占Bash的屏幕,非常的郁闷!但当我们想Ctrl+C来终止的时候,却又无能为力——因为在Bash下你Ctrl+C根本无法终止这个后台运行的程序!

为了防止这种情况,我们需要用到重定向(Redirection),如果你不太清楚,可以本博客之前的博文《Linux下高效编写Shell-Shell特殊字符汇总》篇里面的重定向,代码变化不大,类似下面这样:

## 重定向输出到/dev/null这个特殊文件
## 也就是没有输出内容了
ping blog.useasp.net &>/dev/null &

当然,我们一般更希望后台运行的程序的输出能够保存到指定文件,而不是直接丢弃,所以更一般形式是:

ping blog.useasp.net >>/tmp/background_programs.log 2>&1 &
## 想想这是什么意思?

但我们在这里是要Bash界面能够不被后台的程序搞砸。——毫无疑问,我们前一种已经达到了我们要的效果。

 恩,迄今为止我们已经能够将程序放到后台运行了,但是,对于已经占据我们Bash的程序,我们却无能为力,为了不让它们继续霸占我们的Bash屏幕,我们迄今能做的只有Ctrl +C,让它见鬼去吧!这样我们跑了很久的程序也就终结了,不过,运行的数据可能也没有了。也许更温柔一点是个不错的选择——Ctrl+Z

Ctrl+Z是让程序暂停,在已经运行的程序上直接按下Ctrl+Z,他们就会非常自觉的将自己挂起,并放入到后台中,此时的程序是处于停止状态的,如果要让他在后台运行,就还要用到后面将学到的命令。但此时,我们的Bash屏幕能恢复干净清爽才最主要。

 好了,在这难得平静的Bash界面上,让我们来学习下的一个命令吧,也许我们后台已经有一堆程序在跑呢,我们怎么也得看看才放心,命令就是让我们干这个事情的:

jobs [-lnprs] [jobspec ...] or jobs -x command [args]
参数:
-l    列出后台程序的job number,PID, 状态和命令串
-n    显示自从上次用户知晓状态后程序改变过状态的程序
-r    仅列出正在后台运行(RUNNING)的程序
-s    仅列出后台中处于停止(STOPPED)的程序
更详细的内容可以参看man,这里基本够我们用了。

用用看,你也许会发现你的后台有很多程序在运行哦,同时你也会看到一些不同的地方,比如:

jobs -l
[1]- 10314 Running                 ping blog.useasp.net &>/dev/null &
[2]+ 10833 Stopped                 emacs (wd:~)

中括号后面的竟然有+和-号,这是什么?这个是Bash根据我们放入后台的顺序的一个标记,+号表示最近被放到后台的程序,-号次之,如果有三个以上,我们就会发现第三个以上是没有+/-符号的。而下面我们将要看到的fg在取出后台程序的时候,+号在默认情况下就是那个被切换到前台的程序了。

既然上面我们说了,那就看看它是干什么的。fg应该是foreground的简写,即前台,它的作用是将在后台的程序切换到前台来运行。在切换的时候,fg可以指定参数——Job Number!

## 使用上面的jobs -l中的例子
fg       ## 这个切换到前台运行的程序将会是emacs——Why?

## 或者我们使用下面这种形式

fg %1    ## 切换到前台的将会是ping blog.useasp.net &>/dev/null &
## 此时你可以使用Ctrl+Z将其放回到后台,jobs查看之后你会发现,ping的最后没有了&了。
## 好神奇——想想为什么?

fg -     ## 这个是将-号那个程序切换到前台运行。
## 上述的例子中就是job number为1的程序 ping blog.useasp.net &>/dev/null &

有foreground,自然应该有background了,Yes,它的简写就是!相对应的,bg就是将程序切换到后台运行,注意:不仅切换到后台,更重要的是要在后台运行。Ctrl+Z只是把程序放入后台,但状态是停止。前面我们说过,我们可以将Ctrl+Z放入后台,并将已经停止的程序在后台运行的命令就是它了。来看看是怎么做到的吧:

ping blog.useasp.net &>/dev/null
## 这个将会占用Bash屏幕,因此我们在这里Ctrl+Z将它放入后台
## [2]+  Stopped                 ping blog.useasp.net &>/dev/null

jobs -l
## 此时我们使用jobs来查看,可以发现ping 这个程序已经是STOPPED了
## [1]-  Stopped                 emacs  (wd: ~)
## [2]+  Stopped                 ping blog.useasp.net &>/dev/null

## 让我们想办法让ping在后台继续运行
bg %2
## 此时ping将被放到后台运行
## [2]+ ping blog.useasp.net &>/dev/null &

jobs -l
## 查看下当前的状态:
## [1]+  Stopped                 emacs  (wd: ~)
## [2]-  Running                 ping blog.useasp.net &>/dev/null &
## 已经在后台运行了。

 到此为止,你基本上可以在下熟练的管理在Bash上程序了。当然,这些只是对程序的运行态进行管理,对程序本身并没有影响,那在实际操作中我们有一类操作是会影响程序本身的,比如:重启程序,关闭程序。而这类操作我们要使用的是另外一个命令:kill

命令能够通过信号来控制运行中的程序:

kill -SIGNAL %jobNumber
## -SIGNAL可以通过kill的-l(小写的L)参数列出本机能够支持的信号(SIGNAL)列表
## 常用的SIGNAL有:
## 信号值   信号名        描述
##   -2    SIGINT     终端产生的中断,Ctrl+C
##   -9    SIGKILL    强制关闭程序(KILL),直接杀死
##   -15   SIGTERM    退出程序运行(TERMINATION)
##                    这个和强制关闭不同,这个是程序正常退出的流程
## 如果不带SIGNAL,则默认是-15,以正常的方式退出程序

## 当然,我们更常用的可能是kill的另外一个用法
kill -SIGNAL PID
## 通过PID来kill程序
## 如果要一次性移除多个程序,也许你会想用:
killall ping

有了这些命令,我们就能将尽可能剥削系统的资源,而不至于让我们累个半死,系统闲的要死了。不会剥削系统资源的操作者不是好管理员!

 有了这些命令的时候,你也许很兴奋,终于,我们可以在我们不在系统上的时候,让系统能够为我们做事了,于是,愉快在bash上写上了无数以&结尾的命令,然后,妥妥的关闭了我们的远程连接——恭喜你,你被耍了!系统也是会偷懒的,谁叫你不好好监工呢,如果你不想自己监工,那么请一个吧:nohup

的作用就是让我们的程序在我们退出远程登录(登出系统)的时候,能够不受到影响而继续执行,不过要注意,nohup并不直接支持Bash内建的命令,请使用Shell脚本将命令放在文件中,而后使用nohup执行你的Shell脚本,这才能稳稳的保证系统不偷懒!

nohup Command [parameters] &
## 将程序用nohup在后台运行
## Command是我们的Shell脚本或是非bash内建命令
## parameters非必须,是传递给Command的参数
## &放到后台运行
## 使用nohup运行的命令,会自动的将所有的输出重定向到当前用户的根目录下面的nohup.out文件

 当然,除了nohup,你也可以使用其他的命令来达到同样的目的,比如下面这些都可以

  1. at:不过at需要先启用,这个就是Windows下的计划任务嘛。具体的这里不展开了,又可以写上很多,有兴趣可以参考at的文档;
  2. setsidsetsid command,该命令使我们的命令的父进程是init,而不是当前Bash,只有关机,该程序才会退出;
  3. (command &):这个和上面的类似,也是将父进程设置为了init;
  4. disown:我们使用&来让程序在后台运行,之后我们可以根据该程序的Job Number,使用disown -h %job_number来将程序不受HANGUP信号影响;

举栗子总是更容易让人明白:

setsid ping blog.useasp.net &>/dev/null
## 让ping运行在一个新的会话当中,当然,会话的用户还是当前用户

(ping blog.useasp.net &>/dev/null &)
## 同上

ping blog.useasp.net &>/dev/null &
## 返回:
## [1] 24074
disown -h %1
## 脱离当前用户的信号控制
## disown后查看父进程,还是能看到ping是挂在当前bash
## 但重登录之后,就可以发现ping的父进程是init

 如果你要查看进程关系,可以试试pstree

OK,打完收工

Wednesday, June 18, 2014 | Unix & Linux

文章评论

  • # re: Linux任务的高级管理:程序后台运行及控制
    只是补充:比起nohup这个命令,另一个程序screen可以更方便做到远程连接断开后程序继续执行
  • # re: Linux任务的高级管理:程序后台运行及控制
    @latentlong:
    谢谢,受教,看了下,这个说是在机器上创建一个Session来保证不断线的。下次我试试。
  • # re: Linux任务的高级管理:程序后台运行及控制
    因为screen和emacs的快捷键很像,所以我很喜欢用。而且能开好多个shell
  • # re: Linux任务的高级管理:程序后台运行及控制
    Emacs开始用很难用,上手有点难度,后面有习惯后,用其他的反而不习惯了。

发表评论

Please add 2 and 6 and type the answer here:

关于博主

  一枚成分复杂的网络IT分子,属于互联网行业分类中的杂牌军。