导言
多种后台运行方法总结,nohup, disown, setsid, (...&), screen, tmux
远程登录服务器时常需要长时间运行任务,由于网络不稳定或logout等因素造成连接断开,会导致前台任务运行中断。
该现象与SIGHUP
信号有关
POSIX-compliant
平台(Solaris,MacOS 等)[1]上,当终端logout时,该终端下所有进程会收到SIGHUP
信号huponexit
为on
时(可通过shopt
命令设置),终端logout会给该终端所有进程发送SIGHUP
信号注:注意当通过直接关闭终端窗口,而非通过logout
,exit
等命令退出当前终端时,不论shopt
设置,终端都会给其下所有进程发送SIGHUP
信号。
实现进程免受终端SIGHUP
信号影响的原理主要有两种:
SIGHUP
信号,如nohup
SIGHUP
信号自然不会引起进程中断,如disown
,setsid
新建测试脚本,打印获取的信号到文件方便查看:
[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
进程会屏蔽进程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 ~]#
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
将一个或多个命名包含在“()”中可以使这些命令在子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
对于已经在运行的任务,nohup
和setsid
明显已经不适用,可通过作业调度和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
信号。那如果从终端本身解决问题,即,使终端不关闭呢?那就是 screen
、 tmux
了!
Screen is a full-screen window manager that multiplexes a physical terminal between several processes (typically interactive shells).
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 微信公众号,前往查看
如有侵权,请联系 cloudcommunity@tencent.com 删除。
本文参与 腾讯云自媒体同步曝光计划 ,欢迎热爱写作的你一起参与!