来思考几种场景:

  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. JMeter性能测试基础 (3) - 使用参数文件做搜索引擎性能对比

    本篇文章主要对如何在JMeter中进行URL的参数进行配置进行介绍,通过CSV文件配置参数数据,对baidu.sogou.haosou进行搜索性能对比测试. 1.建立测试计划.线程组,并在线程组下添加 ...

  2. [日常工作] SQLSERVER 数据库出问题..搜索到的有用的网页信息

    Finding a table name from a page ID By: Paul Randal Posted on: September 25, 2014 1:42 am   (Check o ...

  3. 如何规范 CSS 的命名和书写

    我开始学前端的时候也是对于规范问题头疼,后来看了网易的NEC规范,惊呼牛逼 NEC : 更好的CSS样式解决方案 只遵循横向顺序即可,先显示定位布局类属性,后盒模型等自身属性,最后是文本类及修饰类属性 ...

  4. CF235C_Cyclical Quest

    很好的一个自动机的题目. 给原串,和若干个询问串.求原串里有多少个不同子串可以通过询问串循环移动得到. 有点类似求两个串的lcs,但是灵活一点. 首先我们把询问串长度扩大一倍,去掉最后一个字符.因为最 ...

  5. THUWC2017颓废记

    2.9翘掉Wc闭幕式,和石家庄大爷们坐一辆车去杭州…路上日常orz gzz.2.10早上来报到,拍照.宿舍里另外四个人都是GD大爷.开幕式是喜闻乐见的thu日常黑pku(“在中国,世界一流大学有两所, ...

  6. java并发编程中CountDownLatch和CyclicBarrier的使用

    在多线程程序设计中,经常会遇到一个线程等待一个或多个线程的场景,遇到这样的场景应该如何解决? 如果是一个线程等待一个线程,则可以通过await()和notify()来实现: 如果是一个线程等待多个线程 ...

  7. GPU并行编程小结

    http://peghoty.blog.163.com/blog/static/493464092013016113254852/ http://blog.csdn.net/augusdi/artic ...

  8. Python 爬虫入门(一)

    毕设是做爬虫相关的,本来想的是用java写,也写了几个爬虫,其中一个是爬网易云音乐的用户信息,爬了大概100多万,效果不是太满意.之前听说Python这方面比较强,就想用Python试试,之前也没用过 ...

  9. GDB调试工具

    1.运行代码的三种情况     a.运行时有逻辑问题     gdb a.out 设置断点 单行执行     b.运行代码没有退出  一直运行 结束不了         挂载调试    跟踪调试 -g ...

  10. 为什么 “return s and s.strip()” 在用 filter 去掉空白字符时好使?

    如题: 给定一个数组,其中该数组中的每个元素都为字符串,删除该数组中的空白字符串. _list = ["A", "", "", " ...