【问题标题】:Difference between starting a background process in BASHRC vs Command Line在 BASHRC 与命令行中启动后台进程之间的区别
【发布时间】:2019-11-06 22:24:40
【问题描述】:

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

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

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

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

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

有什么区别,我怎样才能阻止 bashrc 启动的“守护进程”在 shell 退出时被杀死。

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 中启动进程?

【问题讨论】:

  • 你能用pstree -gTt 命令告诉我们谁拥有谁吗?
  • 我无法重现这一点:在我的机器上,program 在注销后继续运行,即使从 .bashrc 开始,如您的示例所示
  • @Mathieu 被取消的后台进程的 PPID 为 0。既不是 init,也不是 bash。 bash 如何被杀死并不重要,当它死亡时,后台进程也会死亡。

标签: linux bash shell unix


【解决方案1】:

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

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

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

ps -ef 输出的 PPID 显示 PPID 是 init(第一个启动的进程):

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

当从终端运行时,进程将继续,直到 init 停止。

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

【讨论】:

  • 好吧,这有点道理......我想......但它并没有解释为什么有区别,或者如何让后台进程在 bashrc 中启动,不再有 bash 作为父母。 PS:我确实尝试过双重背景,但也许我做错了。我会做一些进一步的实验。
  • 尝试生成另一个 Bash 实例并从其中启动进程。不过,我不得不质疑从您的.bashrc 启动后台进程是否明智——如果您启动多个 Bash 实例以进行交互使用会发生什么?你如何控制这个过程?它提供了哪些其他方式无法提供的服务?
  • @tripleee 注意我会考虑使用 crontab @reboot 代替的钱
  • 检查进程是否已经在运行,如果是,则另一个没有运行。启动进程从来都不是问题,在shell退出后保持进程运行才是问题。
  • 不...经过进一步调查,PPID 不是问题。 bash 的“disown”程序似乎将进程父进程设置为 0。但进程继续属于 shell PGID,但前提是从 bashrc 启动。
【解决方案2】:

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

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

但是,我仍然觉得奇怪的是,从“.bashrc”后台运行的程序继承了与父 shell 相同的进程组,但命令行中完全相同的后台命令得到了自己的单独进程组。

一旦我发现这是原因,我发现 BASH 手册页中提到了进程组,关于后台进程,尽管它没有提到在“.bashrc”与 CLI 中启动它的区别。

【讨论】:

    【解决方案3】:

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

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

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

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

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

    blah=$(sleep 1000 | sleep 1000)
    

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

    nohup &lt;command&gt;本身不会启动新的进程组,它只会ignoresSIGHUP然后执行command

    Linux(和其他操作系统,当您安装类似util-linux 的东西时)有一个命令setsid 将来自nohup 的do what you expected(但没有得到):setsid command 将create a new process group 用于@ 987654338@ 并使其成为新会话的会话负责人。这个新进程组的PGID 对调用者来说是未知的(在本例中为bash),因此我们不再需要使用nohup。

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

    【讨论】:

    • 谢谢汉斯,它提供了准确的解释以及我需要的解决方案。我已将此标记为首选解决方案。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-01-27
    • 2014-03-31
    • 1970-01-01
    • 1970-01-01
    • 2014-04-25
    • 2019-07-19
    相关资源
    最近更新 更多