linux杂谈之程序后台运行

之前写的一篇bash工作管理

一    场景引入

       我们经常会碰到这样的问题,用 telnet/ssh 登录了远程的 Linux 服务器,运行了一些耗时较长的任务, 结果却由于网络的不稳定导致任务中途失败。如何让命令提交后不受本地关闭终端窗口/网络断开连接的干扰呢?

当用户注销(logout)或者网络断开时,终端会收到 HUP(hangup)信号从而关闭其所有子进程。

因此,我们的解决办法就有两种途径

    1)要么让进程'忽略 HUP 信号'  -->  'nohup'

    2)要么让进程运行在'新的会话里'从而成为"不属于此终端的子进程" -->  'setsid'

二    案例

可以'针对不同的场景'选择'不同的方式'来处理这个问题

(1)nohup

(1)  nohup命令 可以将'程序以忽略挂起信号'的方式运行'running'起来,被运行的程序的输出信息将'不会显示到终端'

(2)  无论是否将 nohup 命令的输出重定向到终端,输出都将'附加到'当前目录的 'nohup.out' 文件中

(3)  如果当前目录的 nohup.out 文件'不可写',输出'重定向到$HOME/nohup.out文件中'

(4)  如果'没有文件'能创建或打开以用于追加,那么 'command 参数'指定的命令'不可调用'

(5)  如果标准错误'是一个终端',那么把指定的命令写给'标准错误的所有输出'作为标准输出重定向到相同的文件描述符

案例

1:  '脚本(或者command)方式后台运行' -->  '不产生nohup.txt'

nohup  ./shell.sh &> /dev/null &

2:  '将错误输出也伪装成标准输入'

nohup command > myout.file 2>&1 &

注意细节

正确方式:  当shell中'提示了nohup成功后'还需要'按终端上键盘任意键'退回到shell输入命令窗口,然后通过在shell中'输入exit来退出终端'

错误方式:  而我是每次在nohup执行成功后'直接点关闭程序按钮关闭终端',所以这时候会'断掉该命令所对应的session',导致nohup对应的进程被通知需要一起shutdown。

(2)setsid

setsid命令子进程'从父进程继承了':SessionID、进程组ID和打开的终端,子进程如果'要脱离这些',代码中可通过'调用setsid来实现'

命令行或脚本中可以通过使用命令setsid来运行程序实现。setsid'帮助一个进程脱离从父进程继承而来的已打开的终端'、隶属进程组和隶属的会话。

--- '更加通俗的理解' ---

setsid中的sid指的是session id,意指以该命令运行的进程是一个'新的session',因此'其父进程id不属于当前终端',实际上,setsid运行的进程,其'父进程id(PPID)为1'(init 进程的 PID)

ps -ef |grep    -->  '可以查看ppid=1'

使用方法同上

注意

setsid输出重定向必须'手动指定'

二者的关系

由于nohup的父进程与'当前的worker有关',当我们Ctrl+C的时候'没有放到后端',也会'把其给kill掉'。

而setsid的'父进程是init',所以当我们'退出worker的时候',并'不会kill掉该服务'

(3)subshell

First:  将一个或多个命令包含在'()'中就能让这些命令在'子 shell 中'运行中

Second: 将"&"也放入'()'内之后,我们就会发现'所提交的作业并不在作业列表中',也就是说是'无法通过jobs来查看'的
(ping 172.25.2.100 &)

ps -ef |grep ping

补充说明

'jobs' 可以看到'该进程的父进程'是当前shell的进程号

(4)disown

场景引入:我们已经知道,如果事先在命令前加上 nohup 或者 setsid 就可以避免 HUP 信号的影响。但是如果我们未加任何处理就已经提交了命令,对于已经在后台运行的命令,该如何补救才能让它避免 HUP 信号的影响呢?

用法

disown -h %'jobspec' 来使某个作业 '忽略HUP信号'

disown -ah           来使'所有的'作业都忽略HUP信号

disown -rh           来使'正在运行'的作业 忽略HUP信号
(1)  disown是'bash内部命令',nohup是外部命令

(2)  disown跟bg,fg一样是'针对job'进行操作,nohup是针对'命令'操作

(3)  退出后'归属于init进程管理'

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

备注:  '最后一条似乎没有生效'

 

说明:只有'当前终端'退出后,才会隶属于'init'进程管理  -->  再'开启一个'终端查看

案例展示


disown (如果'提交命令时''未使用&将'命令放入后台运行,可使用' CTRL-z '和'bg'将其放入后台,再使用"disown")

[root@pvcent107 build] ' cp -r testLargeFile largeFile2'

[1]+  Stopped                 cp -i -r testLargeFile largeFile2
[root@pvcent107 build] ' bg %1'
[1]+ cp -i -r testLargeFile largeFile2 &
[root@pvcent107 build]  jobs
[1]+  Running                 cp -i -r testLargeFile largeFile2 &
[root@pvcent107 build] 'disown -h %1'
[root@pvcent107 build] ps -ef |grep largeFile2
root      5790  5577  1 10:04 pts/3    00:00:00 cp -i -r testLargeFile largeFile2
root      5824  5577  0 10:05 pts/3    00:00:00 grep largeFile2
[root@pvcent107 build]#

(5)ctrl+z补充

'disown这种方法'的操作对象是'作业',如果我们在运行命令时在结尾加了"&" 来使它成为一个作业并在后台运行,那么就万事大吉了,我们可以通过jobs 命令来得到所有作业的列表。

但是如果起初并'没有把当前命令作为作业来运行',如何才能'得到它的作业号'呢?答案就是用 'CTRL-z(按住Ctrl键的同时按住z键)'了!

CTRL-z 的用途就是'将当前进程挂起'(Suspend),然后我们就可以'用jobs 命令来查询它的作业号',再用'bg jobspec 来将它放入后台'并继续运行。

需要'注意'的是:如果挂起会'影响当前进程的运行结果',请'慎用'此方法。

相关参考

screen, tmux  -->  将进程永远'处在后台运行'是

screen大批量操作

(6)ssh后台运行案例补充

需求:  ssh远程执行脚本并在后台运行  --> 要不要加 'nohup'

ssh root@172.16.146.20 '/usr/local/luly/loadavg.sh 2 &> /dev/null &'

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值