前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >linux 后台运行方法总结

linux 后台运行方法总结

作者头像
PedroQin
发布2020-06-22 17:17:12
3.6K0
发布2020-06-22 17:17:12
举报
文章被收录于专栏:WriteSimpleDemoWriteSimpleDemo

导言

多种后台运行方法总结,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

现象还原

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

代码语言:javascript
复制
[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

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

代码语言:javascript
复制
[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信号,并且任务进程已停止:

代码语言:javascript
复制
[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信号

代码语言:javascript
复制
[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.

......

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

代码语言:javascript
复制
[root@labserver ~]# nohup ./receive_signal.sh
nohup: ignoring input and appending output to 'nohup.out'

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

代码语言:javascript
复制
[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 命令通过在新的会话中运行命令来实现摆脱当前终端控制的目的。

代码语言:javascript
复制
[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信号影响

代码语言:javascript
复制
[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

代码语言:javascript
复制
[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完成此目的

代码语言:javascript
复制
[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 来将挂起的进程放在后台)继续运行。这样我们就可以在一个终端内灵活切换运行多个任务,这一点在调试代码时尤为有用。因为将代码编辑器挂起到后台再重新放回时,光标定位仍然停留在上次挂起时的位置,避免了重新定位的麻烦。

代码语言:javascript
复制
[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

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

代码语言:javascript
复制
[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/

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2020-06-18,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 WriteSimpleDemo 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 问题现象
  • 为什么
  • 实现方式
    • 现象还原
      • nohup
        • setsid
          • subshell特殊用法:( ... &)
            • disown
            • 换个思路
              • screen
                • tmux
                • 参考链接
                领券
                问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档