在BASHRC和命令行中启动后台进程之间的区别

时间:2019-06-25 06:24:58

标签: linux bash shell unix

我正在尝试自动使进程后台运行。

nohup program > /tmp/program.log 2>&1 < /dev/null &
disown

如果我检查进程是否正在运行,并通过“ .bashrc”在登录时启动该程序,则该程序将启动,但退出时会死掉。

但是,如果我在命令行上执行完全相同的命令,则当我退出时,程序将继续在后台运行。

我找不到bashrc启动和cli启动之间的程序环境差异。 (bashrc中几乎没有任何内容)。我对这两种情况的程序的理解应该相同。

有什么区别,当外壳退出时,如何阻止bashrc启动的“守护程序”被杀死。

PS:删除nohup没什么区别。并且我已经看到程序正在运行,然后在退出初始登录时从另一个登录中消失。

在有人说什么之前...在将程序后台放入bashrc后添加“ disown”并不能解决问题!

更新:   如果ssh登录连接被终止(窗口关闭或连接突然终止),则在bashrc中启动的程序将继续运行,但这似乎是因为启动它的bash仍在运行(至少暂时是这样)。 仅当您为bash键入“ exit”或杀死bash(即使信号为9不可捕获!)时,背景才会被杀死。

该程序的PPID(由外壳程序所覆盖)为0,即其父级不是外壳程序,也不是init进程!无论如何启动,都是这种情况。

更新2 ... 从bashrc启动后台程序...

# ps -jA w
   PID   PGID    SID TTY      STAT   TIME COMMAND
   891    891    891 pts/2    Ss+    0:00 /bin/bash
   899    891    891 pts/2    Sl+    0:00 program

我杀死了那个人,然后从命令行启动了它。

   891    891    891 pts/2    Ss+    0:00 /bin/bash
   958    955    891 pts/2    Sl     0:00 program

现在,当外壳存在时,程序不会退出。 因此,看起来唯一的不同是PGID发生了变化。

如何在其他PGID中启动进程?

3 个答案:

答案 0 :(得分:2)

进程组是作业控制所必需的,因为外壳需要一些东西来将作业控制信号发送到例如当您键入fg时。 POSIX.1-2017 states

  

支持作业控制的命令解释器进程可以将终端分配到不同的作业或进程组,方法是将相关的进程放在单个进程组中,并将该进程组与终端相关联

(斜体字是我的)这似乎甚至等同于“进程组”和“作业”的概念,尽管大多数人将术语“作业”用于进程组(甚至外壳程序自己的进程组中的子级),它们是在外壳 job表中注册(并且可以由内置disown从该表中删除)

因此,如果shell不想在作业控制下启动子命令(甚至shell管道),它就不会创建新的进程组(通过调用setpgrp()

例如使用流程替换时

blah=$(sleep 1000 | sleep 1000)

(尝试一下,看看ps -jA w的输出!),显然,从.bashrc启动命令时

nohup <command>本身不会启动新的进程组,只会启动ignores SIGHUP,然后执行command

Linux(以及安装util-linux之类的其他OS)具有命令setsid,该命令将从nohup do what you expected(但没有得到):{ {1}}将create a new process group替换为setsid command,并使其成为新会话的会话负责人。该新进程组的<command>对于调用者而言将是未知的(在这种情况下为PGID),因此我们不再需要使用bash

因此,使用nohup而不是setsid,您就完成了(我现在才看到Mark Plotnick的评论,这对金钱是正确的。哦,希望我的回答也能澄清< em> reason 为什么在这种情况下nohup是更好的选择)

答案 1 :(得分:0)

好的...看来问题实际上是由环境引起的。

shell正在docker容器中运行。似乎Docker Exec是终止同一进程组中所有进程的终端,而不是Shell。或者至少看起来是这样。

但是,我仍然感到奇怪的是,以“ .bashrc”为背景的程序继承了与父外壳程序相同的进程组,但是从命令行获得的完全相同的后台命令却获得了自己的独立进程组。

一旦我找到了原因,就发现在BASH联机帮助页中提到了进程组,其中涉及到对进程进行后台处理,尽管没有提到在“ .bashrc”与CLI中启动进程的区别。

答案 2 :(得分:-1)

每个bash进程都有一个PPID(父PID)

如果从终端运行以下命令:

nohup tail -f /dev/null > /tmp/rand.txt &

ps -ef输出中的PPID显示PPID处于初始化状态(首先启动进程):

UID        PID  PPID  C STIME TTY          TIME CMD
user     18424     1  0 16:17 tty1     00:00:00 tail -f /dev/null

如果从bashrc运行相同的命令,则PPID是bash进程:

UID        PID  PPID  C STIME TTY          TIME CMD
user     16405 16404  0 Jun20 tty2     00:00:08 bash
user     18424 18386  0 16:17 tty1     00:00:00 tail -f /dev/null

从终端运行时,该过程将继续直到初始化停止。

从bashrc运行时,该过程将继续直到bash停止。