专栏首页WriteSimpleDemolinux 后台运行方法总结

linux 后台运行方法总结

导言

多种后台运行方法总结,nohup, disown, setsid, (...&), screen, tmux

问题现象

远程登录服务器时常需要长时间运行任务,由于网络不稳定或logout等因素造成连接断开,会导致前台任务运行中断。

为什么

该现象与SIGHUP信号有关

  • POSIX-compliant平台(Solaris,MacOS 等)[1]上,当终端logout时,该终端下所有进程会收到SIGHUP信号
  • 在Android, FreeBSD, Linux Distributions等平台(遵循大部分POSIX标准, 但是没有认证),当 bash 设置huponexiton时(可通过shopt命令设置),终端logout会给该终端所有进程发送SIGHUP信号

注:注意当通过直接关闭终端窗口,而非通过logoutexit等命令退出当前终端时,不论shopt设置,终端都会给其下所有进程发送SIGHUP信号。

实现方式

实现进程免受终端SIGHUP信号影响的原理主要有两种:

  1. 使进程屏蔽SIGHUP信号,如nohup
  2. 使进程脱离当前终端,这样当前终端的SIGHUP信号自然不会引起进程中断,如disownsetsid

现象还原

新建测试脚本,打印获取的信号到文件方便查看:

[root@labserver ~]# cat receive_signal.sh
#!/bin/bash
trap  trap_1    SIGHUP
trap  trap_2    SIGINT
trap  trap_3    SIGQUIT
trap  trap_15   SIGTERM
PID=$$
function trap_1()
{
    echo `date` PID: [$PID]  trap: [SIGHUP] |tee receive_signal.txt
    sync
}
function trap_2()
{
    echo `date` PID: [$PID]  trap: [SIGINT] |tee receive_signal.txt
    sync
}
function trap_3()
{
    echo `date` PID: [$PID]  trap: [SIGQUIT] |tee receive_signal.txt
    sync
}
function trap_15()
{
    echo `date` PID: [$PID]  trap: [SIGTERM] |tee receive_signal.txt
    sync
}
sleep 30000

执行以下命令后关闭终端窗口:

[root@labserver ~]# ./receive_signal.sh &
[1] 51995
[root@labserver ~]# ps -ef|grep receive_signal
root     51995 51951  0 23:02 pts/12   00:00:00 /bin/bash ./receive_signal.sh
root     51998 51951  0 23:02 pts/12   00:00:00 grep --color=auto receive_signal

查看 receive_signal.txt 已捕捉到SIGHUP信号,并且任务进程已停止:

[root@labserver ~]# cat receive_signal.txt
Tue Jun 16 23:02:52 CST 2020 PID: [51995] trap: [SIGHUP]
[root@labserver ~]# ps -ef|grep receive_signal
root     52035 31396  0 23:03 pts/11   00:00:00 grep --color=auto receive_signal

nohup

顾名思义,nohup进程会屏蔽进程SIGHUP信号

[root@labserver ~]# man nohup
NAME
       nohup - run a command immune to hangups, with output to a non-tty

SYNOPSIS
       nohup COMMAND [ARG]...
       nohup OPTION

DESCRIPTION
       Run COMMAND, ignoring hangup signals.

......

执行以下命令并关闭终端窗口

[root@labserver ~]# nohup ./receive_signal.sh
nohup: ignoring input and appending output to 'nohup.out'

查看进程依旧存在,而且其 PPID 变为了1(关闭终端窗口前其PPID为登陆shell PID)。

[root@labserver ~]# ps -ef|grep receive_signal
root     52304     1  0 23:05 ?        00:00:00 /bin/bash ./receive_signal.sh
root     52327 31396  0 23:05 pts/11   00:00:00 grep --color=auto receive_signal
[root@labserver ~]# cat receive_signal.txt
[root@labserver ~]#

setsid

setid 命令通过在新的会话中运行命令来实现摆脱当前终端控制的目的。

[root@labserver ~]# man setsid
NAME
       setsid - run a program in a new session

SYNOPSIS
       setsid program [arg...]

DESCRIPTION
       setsid runs a program in a new session.

OPTIONS
       -c, --ctty
              Set the controlling terminal to the current one.
......

执行以下命令并查看进程,进程PPID为1,不受当前终端SIGHUP信号影响

[root@labserver ~]# ps -ef|grep receive_signal
root     57311 56592  0 23:51 pts/11   00:00:00 grep --color=auto receive_signal
[root@labserver ~]# setsid  ./receive_signal.sh
[root@labserver ~]# ps -ef|grep receive_signal
root     57313     1  0 23:51 ?        00:00:00 /bin/bash ./receive_signal.sh
root     57324 56592  0 23:52 pts/11   00:00:00 grep --color=auto receive_signal

subshell特殊用法:( ... &)

将一个或多个命名包含在“()”中可以使这些命令在子shell 中运行中,将"&"也放入“()”内之后,可实现子shell脱离当前终端,从而摆脱当前终端SIGHUP信号影响 Tips:

()经常在脚本中做目录切换时使用,在子shell的目录切换不会影响到父shell。故可省去频繁的目录切换

执行以下命令并查看进程,进程PPID为1

[root@labserver ~]# ps -ef|grep receive_signal
root     58725 56592  0 00:02 pts/11   00:00:00 grep --color=auto receive_signal
[root@labserver ~]# (./receive_signal.sh &)
[root@labserver ~]# ps -ef|grep receive_signal
root     58727     1  0 00:02 pts/11   00:00:00 /bin/bash ./receive_signal.sh
root     58735 56592  0 00:02 pts/11   00:00:00 grep --color=auto receive_signal

disown

对于已经在运行的任务,nohupsetsid明显已经不适用,可通过作业调度和disown完成此目的

[root@labserver ~]# help disown
disown: disown [-h] [-ar] [jobspec ...]
    Remove jobs from current shell.
    
    Removes each JOBSPEC argument from the table of active jobs.  Without
    any JOBSPECs, the shell uses its notion of the current job.
    
    Options:
      -a        remove all jobs if JOBSPEC is not supplied
      -h        mark each JOBSPEC so that SIGHUP is not sent to the job if the
        shell receives a SIGHUP
      -r        remove only running jobs
    
    Exit Status:
    Returns success unless an invalid option or JOBSPEC is given.

当前台已经执行任务时,使用Ctrl z将当前进程挂起到后台暂停运行,使用bg %1命令使后台挂起命令继续运行,再使用disown -h %1使进程忽略SIGHUP信号。 另,使用 disown %1 也可达到相同效果,不过当前任务会从任务列表移除,但仍可以通过ps查看进程 Tips:

在我们的日常工作中,我们可以用 Ctrl z 来将当前进程挂起到后台暂停运行,执行一些别的操作,然后再用 fg 来将挂起的进程重新放回前台(也可用 bg 来将挂起的进程放在后台)继续运行。这样我们就可以在一个终端内灵活切换运行多个任务,这一点在调试代码时尤为有用。因为将代码编辑器挂起到后台再重新放回时,光标定位仍然停留在上次挂起时的位置,避免了重新定位的麻烦。

[root@labserver ~]# ps -ef|grep receive_signal
root      1918  1878  0 11:49 pts/16   00:00:00 grep --color=auto receive_signal
[root@labserver ~]# jobs
[root@labserver ~]# ./receive_signal.sh
^Z
[1]+  Stopped                 ./receive_signal.sh
[root@labserver ~]# jobs
[1]+  Stopped                 ./receive_signal.sh
[root@labserver ~]# bg %1
[1]+ ./receive_signal.sh &
[root@labserver ~]# jobs
[1]+  Running                 ./receive_signal.sh &
[root@labserver ~]# disown -h %1
[root@labserver ~]# jobs
[1]+  Running                 ./receive_signal.sh &
[root@labserver ~]# ps -ef|grep receive_signal
root      1919  1878  0 11:50 pts/16   00:00:00 /bin/bash ./receive_signal.sh
root      1947  1878  0 11:50 pts/16   00:00:00 grep --color=auto receive_signal

关闭窗口后查看进程信息,如下

[root@labserver ~]# ps -ef|grep receive_signal
root      1919     1  0 11:50 ?        00:00:00 /bin/bash ./receive_signal.sh
root      2044 54439  0 11:51 pts/12   00:00:00 grep --color=auto receive_signal

换个思路

前面的方法都是想办法避免接受终端因logout、网络等因素关闭时的SIGHUP信号。那如果从终端本身解决问题,即,使终端不关闭呢?那就是 screentmux了!

screen

Screen is a full-screen window manager that multiplexes a physical terminal between several processes (typically interactive shells).

tmux

tmux is a terminal multiplexer: it enables a number of terminals to be created, accessed, and controlled from a single screen. tmux may be detached from a screen and continue running in the background, then later reattached. 原文链接:tmux,你需要的终端神器

参考链接

[1] Posix Standard(https://linuxhint.com/posix-standard/) [2] https://unix.stackexchange.com/questions/3886/difference-between-nohup-disown-and [3] man 7 signal [4] https://www.ibm.com/developerworks/cn/linux/l-cn-nohup/

本文分享自微信公众号 - WriteSimpleDemo(this_is_a_wechat),作者:PedroQin

原文出处及转载信息见文内详细说明,如有侵权,请联系 yunjia_community@tencent.com 删除。

原始发表时间:2020-06-18

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • shell脚本一步完成多层ssh跳转时的文件传输

    由于工作中,经常需要ssh连接到产线服务器进行代码调试。中间经过3层,4层甚至更多层跳转。这就导致在实际操作时常常面临两个问题:

    PedroQin
  • UEFI/LEGACY 可启动ISO制作

    搭配前文简易Ramdisk 镜像制作(基于Centos7+)中Ramdisk可实现:

    PedroQin
  • 实时同步文件到远程服务器:Lsyncd - Live Syncing (Mirror) Daemon

    最近由于业务需求,另外架设了台服务器,多个服务器共同承担生产环境的测试。多个服务器服务于同一生产环境就需要这多个服务器之间保持生产测试程式的同步,甚至各种生产记...

    PedroQin
  • 常与无常:SQL语句中常量的处理及性能差异解析

    杨廷琨,网名 yangtingkun 云和恩墨技术总监,Oracle ACE Director,ACOUG 核心专家 在ITPUB论坛上看到一个有意思的问题:两...

    数据和云
  • Redis 群集部署

    一、Redis群集相关概念 Redis是从3.0版本开始支持cluter的,采用的是hash槽方式,可以将多个Redis实例整合在一起,形成一个群集,也就是将数...

    小手冰凉
  • 利用 Grafana 和 Arthas 自动抓取异常Java进程的线程堆栈

    近期发现业务高峰期时刻会出现CPU繁忙导致的timeout异常,通过监控来看是因为Node上面的一些Pod突发抢占了大量CPU导致的。

    落跑架构师M
  • JS数据结构第六篇 --- 二叉树力扣练习题

    比如输入:[3, 9, 20, 15, 7, 88, 16,  2, 19, 13, 26, 11]

    tandaxia
  • 数据结构07 二叉树

    这篇文章开始总结 树和二叉树。 什么是树呢? 1、树的定义 (1)有且仅有一个特定的称为根(root) 的节点。 (2)当 n>1 时,其余节点可分为 m(m>...

    nnngu
  • Vue 2.x折腾记 - (21) CNZZ统计在引流页中的应用姿势

    若是我们要考虑下维护性,基于 vue cli 3 构建项目的小伙伴可以用脚手架封装的特性来抽离;

    CRPER
  • 页面审核工具 Chrome Lighthouse 简介[每日前端夜话0x88]

    Chrome Lighthouse 已经存在了一段时间了,但如果我要求你解释一下它能做什么,你能解释清楚吗?

    疯狂的技术宅

扫码关注云+社区

领取腾讯云代金券