程序后台运行

作者: | 更新日期:

以前知道nohup可以使初次运行的程序后台运行, 但是其他情况的程序就没办法了, 这里完善的记录一下各种情况后台运行的操作.

本文首发于公众号:天空的代码世界,微信号:tiankonguse

背景

经常会遇到这样一个问题, ssh登陆远程服务器, 运行一些程序. 后来退出时没跑完的程序也退出了.
即使我们加上& 命令, 没跑完的程序依旧退出.
这篇文章就记录我们该如何让程序后台运行, 我们ssh退出的时候程序不退出.

原因

我们ssh登陆后, 运行的程序都是当前登陆会话的子进程.
会话关闭后, 子进程都被关闭了.
所以解决方案就是让后台运行的进程不是当前会话的子进程.

启动时转后台

### nohup

nohup 是我最常用的手法. nohup 的作用就是忽略hangups信号.
使用简单, 直接放在命令前面即可.
默认标准输出和标准错误缺省会被重定向到 nohup.out 文件中。
一般我们可在结尾加上&来将命令同时放入后台运行,也可用>filename 2>&1来更改缺省的重定向文件名。

# nohup - run a command immune to hangups, with output to a non-tty
nohup myapp --start > ../log/some.log  2>&1 &

setsid

setsid 的功能是创建一个新会话, 也能满足我们的要求.

# setsid - run a program in a new session
setsid myapp --start > ../log/some.log  2>&1 &

shell小技巧

我们知道,将一个或多个命名包含在()中就能让这些命令在子 shell 中运行中,从而扩展出很多有趣的功能,我们现在要讨论的就是其中之一。

当我们将&也放入()内之后,我们就会发现所提交的作业并不在作业列表中,也就是说,是无法通过jobs来查看的。
让我们来看看为什么这样就能躲过 HUP 信号的影响吧。

(myapp --start > ../log/some.log  2>&1 &)

运行中转后台

有时候我们的任务已经在运行了. 现在我们需要关闭会话, 但是不想停止任务.
这个时候就需要这个小节的知识点了.

disown处理任务

disown [-ar] [-h] [jobspec ...]
    Without options, each jobspec is removed from the table of active jobs.    
    If jobspec is not present, and neither -a nor -r is supplied,  the  shell’s notion  of the current job is used.  
    If the -h option is given, each jobspec is not removed from the table, but is marked so that SIGHUP is not sent to the job if the shell receives a SIGHUP.  
    If no jobspec is present, and neither the -a nor the -r option is supplied, the current job is used.  
    If no  jobspec  is  supplied,  the  -a option means to remove or mark all jobs; 
    the -r option without a jobspec argument restricts operation to running jobs.  
    The return value is 0 unless a jobspec does not specify a valid job.

可以看出,我们可以用如下方式来达成我们的目的。

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

需要注意的是,当使用过 disown 之后,会将把目标作业从作业列表中移除,我们将不能再使用jobs来查看它,但是依然能够用ps -ef查找到它。

正在运行中的任务

可以参考我14年的一篇文章ubuntu 前台程序和后台程序.
我们可以把任务转为后台任务, 然后就可以再使用 disown 来转化为后台程序了.

screen

我们已经知道了如何让进程免受 HUP 信号的影响,但是如果有大量这种命令需要在稳定的后台里运行,如何避免对每条命令都做这样的操作呢?

此时最方便的方法就是 screen 了。
screen 的参数很多,具有很强大的功能,我们在此仅介绍其常用功能以及简要分析一下为什么使用 screen 能够避免 HUP 信号的影响。

NAME
    screen - screen manager with VT100/ANSI terminal emulation

SYNOPSIS
    screen [ -options ] [ cmd [ args ] ]
    screen -r [[pid.]tty[.host]]
    screen -r sessionowner/[[pid.]tty[.host]]

DESCRIPTION
    Screen  is  a  full-screen  window manager that multiplexes a physical
    terminal between several  processes  (typically  interactive  shells).
    Each  virtual  terminal provides the functions of a DEC VT100 terminal
    and, in addition, several control functions from the  ISO  6429  (ECMA
    48,  ANSI  X3.64)  and ISO 2022 standards (e.g. insert/delete line and
    support for multiple character sets).  There is a  scrollback  history
    buffer  for  each virtual terminal and a copy-and-paste mechanism that
    allows moving text regions between windows.

使用 screen 很方便,有以下几个常用选项:

  • screen -dmS session name来建立一个处于断开模式下的会话(并指定其会话名)。
  • screen -list 来列出所有会话。
  • screen -r session name来重新连接指定会话。
  • 用快捷键CTRL-a d 来暂时断开当前会话。

当我们用-r连接到 screen 会话后,我们就可以在这个伪终端里面为所欲为,再也不用担心 HUP 信号会对我们的进程造成影响,也不用给每个命令前都加上nohup或者setsid了。

总结

现在几种方法已经介绍完毕,我们可以根据不同的场景来选择不同的方案。
nohup/setsid 无疑是临时需要时最方便的方法,disown 能帮助我们来事后补救当前已经在运行了的作业,而screen 则是在大批量操作时不二的选择了。

本文首发于公众号:天空的代码世界,微信号:tiankonguse
如果你想留言,可以在微信里面关注公众号进行留言。

关注公众号,接收最新消息

tiankonguse +
穿越