来思考几种场景:

  1、某个脚本需要执行时间比较长,无人值守,可能执行过程中因ssh会话超时而中断?

  2、某次测试一段代码,需要临时放入后台运行?

  3、放入后台运行的脚本,需要在一段时间后重新调到前台?

  4、已经调起作用后,忽然发现没有将作业放入后台执行,如何补救?

  5、需要在后台运行大量的脚本,如何管理?

一、问题分析与思路

  当终端关闭或网络断开时,当前终端中运行的进程就会收到SIGHUP(终止信号),终端关闭,终端进程之下的所有子进程也会关闭。

为此,我们可以考虑:

  (1)有没有方法让运行中的进程不再收到SIGHUP信号

  (2)有没有方法让运行中的进程独立存在,不属于当前终端的子进程

二、shell/命令/作业后台执行方法

1、nohup

nohup的用途就是让提交的命令忽略hangup信号。语法如下:

# nohup --help
用法:nohup 命令 [参数]...
 或:nohup 选项
忽略挂起信号运行指定的命令。

(1)使用

  nohup的使用比较简单,只需在要处理的命令前加上 nohup 即可,标准输出和标准错误缺省会被重定向到nohup.out文件中。

使用时,常见的有以下几种方式:
  (1)一般我们可在结尾加上"&"来将命令同时放入后台运行;
  (2)">filename 2>&1"来更改缺省的重定向文件名;
  (3)直接">/dev/null 2>&1 &"重定向到/dev/null,不记录日志;

注意:
  (1)如果不将 nohup 命令的输出重定向,输出将附加到当前目录的 nohup.out 文件中。
  (2)如果当前目录的 nohup.out 文件不可写,输出重定向到 $HOME/nohup.out 文件中。
  (3)如果没有文件能创建或打开以用于追加,那么 COMMAND参数指定的命令不可调用。
  (4)如果标准错误是一个终端,那么把指定的命令写给标准错误的所有输出作为标准输出重定向到相同的文件描述符。

(2)示例

示例1:直接放入后台运行

[root@vnx ~]# cat a.sh
ping www.baidu.com
[root@vnx ~]# nohup sh a.sh & ##直接放入后台运行
[] 31159 ##进程号
[root@vnx ~]# nohup: 忽略输入并把输出追加到"nohup.out" [root@vnx ~]# ps -ef | grep
root : pts/ :: sh a.sh
root : pts/ :: ping www.baidu.com
root : pts/ :: grep
[root@vnx ~]# ps -ef | grep ping
root : pts/ :: ping www.baidu.com
root : pts/ :: grep ping [root@vnx ~]# kill -
[root@vnx ~]# ps aux | grep
root 0.0 0.0 pts/ S+ : : grep
[root@vnx ~]# ps -ef | grep ping
root : pts/ :: ping www.baidu.com
root : pts/ :: grep ping
[root@vnx ~]# tail -f nohup.out
bytes from 61.135.169.121: icmp_seq= ttl= time=1.56 ms
bytes from 61.135.169.121: icmp_seq= ttl= time=2.02 ms

示例2:重定向到文件

[root@vnx ~]# nohup sh a.sh >tmp.log >& &
[]
[root@vnx ~]# ps -ef | grep
root : pts/ :: sh a.sh
root : pts/ :: ping www.baidu.com
root : pts/ :: grep
[root@vnx ~]# jobs ##查看作业,jobs可以查看nohup提交到后台的作业
[]+ Running nohup sh a.sh > tmp.log >& &
[root@vnx ~]# fg % #将jobs查到的作业调入前台
nohup sh a.sh > tmp.log >&

不记录日志方式与此类似,只是将/dev/null作为重定向的目标。

说明:

()ctrl + z:可以将一个正在前台执行的命令放到后台,并且暂停
()jobs:查看当前有多少在后台运行的命令
jobs 列出当前shell环境中已启动的任务状态,若未指定jobsid,则显示所有活动的任务状态信息;如果报告了一个任务的终止(即任务的状态被标记为Terminated),shell 从当前的shell环境已知的列表中删除任务的进程标识
()fg:将后台中的命令调至前台继续运行
如果后台中有多个命令,可以用 fg %jobnumber将选中的命令调出,%jobnumber是通过jobs命令查到的后台正在执行的命令的序号(不是pid)
()bg:将一个在后台暂停的命令,变成继续执行
如果后台中有多个命令,可以用bg %jobnumber将选中的命令调出,%jobnumber是通过jobs命令查到的后台正在执行的命令的序号(不是pid)

2、setid

setsid能新建一个session,语法如下:

NAME
setsid - run a program in a new session
SYNOPSIS
setsid program [arg...]

示例

[root@vnx ~]# setsid ping www.baidu.com
[root@vnx ~]# PING www.a.shifen.com (220.181.111.188) () bytes of data.
bytes from 220.181.111.188: icmp_seq= ttl= time=3.63 ms
bytes from 220.181.111.188: icmp_seq= ttl= time=4.12 ms
bytes from 220.181.111.188: icmp_seq= ttl= time=4.18 ms [root@vnx ~]# ps -ef |grep ping
root : ? :: ping www.baidu.com ##注意与nohup的区分,这里的父进程号是1(init进程)
root : pts/ :: grep ping
[root@vnx ~]# jobs #这里使用jobs是无法查到相关的作业信息的

注意:setsid与nohup的区分,这里的进程 ID(PID)为31758,而它的父ID(PPID)为1(即为 init进程ID)并不是当前终端的进程ID

说明:当新建一个session后,相当创建了init进程的一个子进程,与当前终端的session便不再关联,自然,关闭终端,也不会对其产生影响。

3、()和&

我们知道在Shell中有这样一个知识点:

(cmd1;cmd2;cmd3)

命令组:在括号中的命令列表,将会作为一个子shell来运行。

(注:在括号中的变量,由于是在子shell中,所以对于脚本剩下的部分是不可用的。父进程,也就是脚本本身,将不能够读取在子进程中创建的变量, 也就是在子shell中创建的变量。)

示例:

[root@vnx ~]# (ping www.baidu.com )                                      ##会话1
PING www.a.shifen.com (220.181.111.188) () bytes of data.
bytes from 220.181.111.188: icmp_seq= ttl= time=5.11 ms
bytes from 220.181.111.188: icmp_seq= ttl= time=3.94 ms
^C
--- www.a.shifen.com ping statistics ---
packets transmitted, received, % packet loss, time 18817ms
rtt min/avg/max/mdev = 3.408/4.026/5.480/0.539 ms
[root@vnx ~]#                                   ##直接用()包围命令,在会话退出后子命令也是会退出的 [root@vnx ~]# ps -ef | grep www.baidu.com ##会话2
root : pts/ :: ping www.baidu.com ##发现子命令的父命令进程是31051
root : pts/ :: grep www.baidu.com
[root@vnx ~]# jobs                               ##jobs作业列表里面没有作业与之对应
[root@vnx ~]# 
[root@vnx ~]# ps -ef | grep www.baidu.com ##会话1中终止后,会话2中就看不到相关子命令的进程了
root : pts/ :: grep www.baidu.com

上面我们知道,&可以将命令放入后台执行,我们尝试将&也放入括号里面:

[root@vnx ~]# (ping www.baidu.com &)                         ##会话1
[root@vnx ~]# PING www.a.shifen.com (61.135.169.125) () bytes of data.
bytes from 61.135.169.125: icmp_seq= ttl= time=6.73 ms
bytes from 61.135.169.125: icmp_seq= ttl= time=9.75 ms
^C                                             ##Ctrl + C不能终止子命令
[root@vnx ~]# bytes from 61.135.169.125: icmp_seq= ttl= time=3.17 ms
bytes from 61.135.169.125: icmp_seq= ttl= time=3.44 ms
bytes from 61.135.169.125: icmp_seq= ttl= time=1.88 ms [root@vnx ~]# ps -ef | grep www.baidu.com ##查看该命令的进程,发现其父进程是1,即init初始进程,故当前终端的hub信号是无法影响到它的
root : pts/ :: ping www.baidu.com
root : pts/ :: grep www.baidu.com
[root@vnx ~]# jobs                          ##jobs作业列表里面是查询不到的
[root@vnx ~]#

  从上面我们可以看到:(cmd1;cmd2;cmd3 &)也可以将命令放入后台执行,效果与setsid类似。

4、disown

  若某次操作中,作业已经提交后发现没有放入后台执行,如何补救才能避免被hup信号影响呢?

  这种情况下,使用setsid、()+&是为时已晚的,只能使用作业调度和disown来解决这个问题。disown命令的语法如下:

disown jobID
disown jobID1 jobID2 ... jobIDN
disown [options] jobID1 jobID2 ... jobIDN

disown的可选参数如下:

-a    Delete all jobs if jobID is not supplied.
-h Mark each jobID so that SIGHUP is not sent to the job if the shell receives a SIGHUP.(使某个作业忽略hup信号)
-r Delete only running jobs.

man手册说明如下:

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 unless a jobspec does not specify a valid job.

下面通过例子进行说明:

(1)没有任何选项的情况下,移除不活动作业

(2)所有的作业都忽略hup信号

[root@vnx ~]# jobs -l
[]+ Running nohup ping www.baidu.com &
[root@vnx ~]#
[root@vnx ~]# disown -a
[root@vnx ~]# jobs -l

(3)只有正在运行的作业忽略hup信号

[root@vnx ~]# jobs -l
[]- Running nohup ping www.baidu.com &
[]+ 停止 ping www.baidu.com
[root@vnx ~]# disown -r
[root@vnx ~]# jobs -l
[] 停止 ping www.baidu.com

(4)当退出会话时,如何保持作业在后台继续运行

方式一:指定作业ID

# disown -h jobID
# disown -h %n ##n为作业号,%%代表当前job

方式二:不指定作业ID

## Step : update system ##
apt-get upgrade &> /root/system.update.log & ## Step : Mark apt-get so that SIGHUP is not sent when you exit and go for tea ##
disown -h ## Step : exit from root shell ##
exit

(5)组合使用方式

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

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

     (2)这种方法的操作对象是作业,如果我们在运行命令时在结尾加了"&"来使它成为一个作业并在后台运行,那么就万事大吉了,我们可以通过jobs命令来得到所有作业的列表。但是如果并没有把当前命令作为作业来运行,如何才能得到它的作业号呢?答案就是用 CTRL-z(按住Ctrl键的同时按住z键)了!
  CTRL-z 的用途就是将当前进程挂起(Suspend),然后我们就可以用jobs命令来查询它的作业号,再用bg jobspec来将它放入后台并继续运行。需要注意的是,如果挂起会影响当前进程的运行结果,请慎用此方法。示例如下:

(6)若提交命令时,已经使用&建命令放入后台执行,则可直接使用disown:

[root@vnx ~]# cp -r /opt/hadoop-2.7. /root/ &
[]
[root@vnx ~]# jobs
[]+ Running cp -i -r /opt/hadoop-2.7. /root/ &
[root@vnx ~]# disown -h %
[root@vnx ~]# jobs
[]+ Running cp -i -r /opt/hadoop-2.7. /root/ &
[root@vnx ~]# ps -ef | grep hadoop
root : pts/ :: cp -i -r /opt/hadoop-2.7. /root/
root : pts/ :: grep hadoop

(7)若提交命令时,未将命令放入后台执行,则先用ctrl + z和bg将命令放入后台执行,然后使用disown:

[root@vnx ~]# cp -r /opt/hadoop-2.7./ /root/
^Z
[]+ Stopped cp -i -r /opt/hadoop-2.7./ /root/
[root@vnx ~]# bg %
[]+ cp -i -r /opt/hadoop-2.7./ /root/ &
[root@vnx ~]# jobs
[]+ Running cp -i -r /opt/hadoop-2.7./ /root/ &
[root@vnx ~]# disown -h %
[root@vnx ~]# jobs
[]+ Running cp -i -r /opt/hadoop-2.7./ /root/ &
[root@vnx ~]# ps -ef | grep hadoop
root : pts/ :: cp -i -r /opt/hadoop-2.7./ /root/
root : pts/ :: grep hadoop

5、screen

  screen是建立一个新的全屏虚拟会话终端,这个会话只有在手动输入exit的时候才会退出,在这个会话里执行的命令不用担心HUP信号会对我们的进程造成影响,因此也不用给每个命令前都加上“nohup”或“setsid”了,非常适合我们有规划的执行大量的后台任务,可以非常方便的让我们对这些后台任务进行管理。

  使用方法:

screen                       ##立即创建并进入一个会话。
screen -dmS {name} ##建立一个处于挂起模式下的会话,并根据我们的需要指定其会话名称。
screen -dmS {name} {script} ##在建立会话时同时执行指定的命令或脚本
screen -list ##列出所有会话。
screen -r {name} ##以独占方式进入指定会话。
screen -x {name} ##以并行方式进入指定会话。
ctrl +ad ##输入快捷键ctrl +a和d,可暂时退出当前会话。
exit ##进入指定会话后执行exit即可关闭该会话。

注:若有兴趣,可尝试用pstree命令查看一下使用screen过程中的进程树,这样会更容易理解!!!

通过以上几种说明,可总结几种情况的使用情境:

nohup/setsid 适用于作业量比较少的情况下;
()+&     适用于测试或写脚本过程中,临时使用;
disown     适用于事后补救当前已经在运行的作业和命令的情况;
screen     最适合有大批量操作时的情况。

为方便理解,可阅读以下参考文档:

Linux 技巧:让进程在后台可靠运行的几种方法(nohup等)  http://blog.csdn.net/zstu_zlj/article/details/51783937

Linux学习:让进程在后台运行的几种方法

fg bg ctrl + z jobs & 等命令  http://www.cnblogs.com/xlmeng1988/archive/2012/06/04/jobs.html

linux中的(),(()),[],[[]],{}的作用  http://blog.csdn.net/damotiansheng/article/details/44196769

Linux / Unix: disown Command Examples – nixCraft  https://www.cyberciti.biz/faq/unix-linux-disown-command-examples-usage-syntax/

Linux运行与控制后台进程的方法:nohup, setsid, &, disown, screen « Hey! Linux.  http://www.heylinux.com/archives/1282.html

本文原始链接:http://www.cnblogs.com/chinas/p/7130378.html,转载请注明出处,谢谢!!!!

shell作业后台执行的方法的更多相关文章

  1. Linux后台执行的方法 - 关闭、退出不影响

    =============================================================================================nohup c ...

  2. ASP.net绑定文本框Enter事件到按钮 ASP.NET执行后台执行JS方法

    txtAccountBarcode.Attributes.Add("onkeydown", "if(event.which || event.keyCode){if (( ...

  3. linux:将job放在后台执行的方法

    本文转自http://www.ibm.com/developerworks/cn/linux/l-cn-nohup/ 我自己在工作需要远程连到公司的开发机,在开发机上运行程序时,一旦退出终端就会导致运 ...

  4. golang在linux后台执行的方法

    go build ./index.go 会生成一个index的运行文件 nohup index & 后台运行index文件 killall index 你可能还要关闭index set GOA ...

  5. shell 后台执行命令

    shell 后台执行命令方法: 1. nohup cmd &          后台会生成 nohup.out 文件 2.cmd >/路径/xx.log &   后台生成 xx. ...

  6. PHP后台执行

    php中实现后台执行的方法: ignore_user_abort(true); // 后台运行set_time_limit(0); // 取消脚本运行时间的超时上限后台运行的后面还要,set_time ...

  7. php中怎么实现后台执行?

    http://www.cnblogs.com/zdz8207/p/3765567.html php中实现后台执行的方法: ignore_user_abort(true); // 后台运行set_tim ...

  8. shell命令、调度工具、后台执行线程和软连接

    一.shell命令 1.后缀.sh 第一行需要加#!/bin/bash 没有的话,需呀sh 命令执行 示例test.sh: #!/bin/bash date ./test.sh 提示没有权限,此时,需 ...

  9. Linux中执行shell脚本的4种方法总结

    bash shell 脚本的方法有多种,现在作个小结.假设我们编写好的shell脚本的文件名为hello.sh,文件位置在/data/shell目录中并已有执行权限. 方法一:切换到shell脚本所在 ...

随机推荐

  1. pygame学习笔记(3)——时间、事件、文字

    转载请注明:@小五义 http://www.cnblogs.com/xiaowuyi 1.运动速率    上节中,实现了一辆汽车在马路上由下到上行驶,并使用了pygame.time.delay(200 ...

  2. 微信小程序 功能函数 购物车商品删除

    // 购物车删除 deleteList(e) { const index = e.currentTarget.dataset.index; let carts = this.data.carts; c ...

  3. IE下Userdata本地化存储

    这两天看了下Discuz x2发帖的实时保存机制,涉及到本地化存储,所以上网查了下,Firefox等支持HTML5的浏览器使用window.localStorage或window.sessionSto ...

  4. BibTex相关

    标签(空格分隔): 杂七杂八的问题 又到了写论文的高峰期(?)在BibTeX中添加参考文献时,发现选项很多,对一些称呼还是一脸懵逼..阿一古,也许是最后一次写论文了,还弄清楚的还是清楚一下吧~ [转自 ...

  5. 【刷题】BZOJ 2002 [Hnoi2010]Bounce 弹飞绵羊

    Description 某天,Lostmonkey发明了一种超级弹力装置,为了在他的绵羊朋友面前显摆,他邀请小绵羊一起玩个游戏.游戏一开始,Lostmonkey在地上沿着一条直线摆上n个装置,每个装置 ...

  6. BZOJ3155:Preprefix sum——题解

    https://www.lydsy.com/JudgeOnline/problem.php?id=3155 最朴素的想法是两棵树状数组,一个记录前缀和,一个记录前缀前缀和,但是第二个我们非常不好修改 ...

  7. 基本数据结构 —— 堆以及堆排序(C++实现)

    目录 什么是堆 堆的存储 堆的操作 结构体定义 判断是否为空 往堆中插入元素 从堆中删除元素 取出堆中最大的元素 堆排序 测试代码 例题 参考资料 什么是堆 堆(英语:heap)是计算机科学中一类特殊 ...

  8. 【AGC003F】Fraction of Fractal

    Description ​ 原题链接 ​ Solution ​ 神题. ​ 定义一个上边界或下边界的格子为"上下接口",当且仅当上下边界该位置的格子都是黑色的. ​ "左 ...

  9. Android O新特性和行为变更总结zz

    https://mp.weixin.qq.com/s/Ezfm-Xaz3fzsaSm0TU5LMw Android O 行为变更https://developer.android.google.cn/ ...

  10. process.nextTick,Promise.then,setTimeout,setImmediate执行顺序

    1. 同步代码执行顺序优先级高于异步代码执行顺序优先级: 2. new Promise(fn)中的fn是同步执行: 3. process.nextTick()>Promise.then()> ...