首页 > 解决方案 > 在 BASHRC 与命令行中启动后台进程之间的区别

问题描述

我正在尝试自动后台处理进程。

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

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

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

我在 bashrc 启动和 cli 启动之间的程序环境中找不到任何区别。(bashrc 中几乎没有任何内容)。我对这两种情况下的程序的理解应该被同等对待。

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

PS:删除 nohup 没有区别。当开始登录退出时,我已经看到程序运行然后从单独的登录中死亡。

在有人说什么之前......在 bashrc 中为程序设置背景后添加“拒绝”并没有解决它!

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

程序的 PPID(被 shell 拒绝)是 0,即它的父进程不是 shell 也不是 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

现在,当 shell 存在时,程序不会退出。所以看起来唯一不同的是PGID改变了。

如何在不同的 PGID 中启动进程?

标签: linuxbashshellunix

解决方案


作业控制需要进程组,因为 shell 需要一些东西来发送作业控制信号,例如当您键入fg. POSIX.1-2017状态

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

(斜体是我的)这似乎甚至等同于“进程组”和“作业”的概念,尽管大多数人使用术语“作业”来表示在贝壳作业表(并且可以通过内置从该表中删除disown

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

例如,在使用进程替换时会发生这种情况

blah=$(sleep 1000 | sleep 1000)

(试试看,看看ps -jA w!)的输出,显然,当从.bashrc

nohup <command>,它本身不会启动一个新的进程组,它只会忽略 SIGHUP然后执行command

Linux(和其他操作系统,当您安装类似的东西时util-linux)有一个命令setsid执行您期望 (但没有得到)的操作nohupsetsid command将为新进程组创建一个新进程组<command>使其成为新会话的会话领导者。调用者(在这种情况下)PGID将不知道这个新进程组的 ,bash因此我们不再需要使用nohup

所以,使用setsid代替,nohup你就完成了(我现在才看到 Mark Plotnick 的评论,这对钱是正确的。哦,我希望我的回答也澄清了为什么setsid这种情况下是更好的选择)


推荐阅读