当 Bash 脚本中的后台使用命令时,为什么 Bash 父进程会先于其子进程退出?

当 Bash 脚本中的后台使用命令时,为什么 Bash 父进程会先于其子进程退出?

假设我有以下简单的 bash 脚本: test_bg.sh

#!/bin/bash
ping www.google.ro &> /dev/null &

如果我直接通过执行它./test_bg.sh并执行ps -ef后续操作,我会看到该进程 ping www.google.ro由 systemd(PID 1)继承,这意味着它的父进程退出了,没有等待它完成,所以我得到了一个孤立进程:

UID          PID    PPID    PGID     SID  C STIME TTY          TIME CMD
root           1       0       1       1  0 Jan07 ?        00:00:21 /usr/lib/systemd/systemd --system --deserialize 21
...
...
...
nimus     461772       1  461771  458695  0 18:59 pts/1    00:00:00 ping www.google.ro

/bin/bash -c "ping www.google.ro &> /dev/null &"如果我也使用的话,当然会发生这种情况。

如果我在没有 的情况下执行脚本中的代码&,那么脚本中的代码如下所示test_fg.sh

#!/bin/bash
ping www.google.ro &> /dev/null 

看起来ps -efj --forest像这样:

UID          PID    PPID    PGID     SID  C STIME TTY          TIME CMD
nimus     458695  458596  458695  458695  0 17:02 pts/1    00:00:00  |       \_ -bash
nimus     461907  458695  461907  458695  0 19:02 pts/1    00:00:00  |           \_ /bin/bash ./test_fg.sh
nimus     461908  461907  461907  458695  0 19:02 pts/1    00:00:00  |               \_ ping www.google.ro

/bin/bash ./test_fg.sh因此,再次 fork() 和 exec() 的分叉进程ping www.google.ro 仍然存在。

当然,ping www.google.ro &> /dev/null &直接从我的主 bash 进程(即会话领导者)执行,我会得到:

[nimus@localhost ~]$ ping www.google.ro &> /dev/null &
[1] 462091
[nimus@localhost ~]$ ps -efj --forest
UID          PID    PPID    PGID     SID  C STIME TTY          TIME CMD
root      458581  351997  458581  458581  0 17:02 ?        00:00:00  \_ sshd: nimus [priv]
nimus     458596  458581  458581  458581  0 17:02 ?        00:00:00  |   \_ sshd: nimus@pts/1
nimus     458695  458596  458695  458695  0 17:02 pts/1    00:00:00  |       \_ -bash
nimus     462091  458695  462091  458695  0 19:10 pts/1    00:00:00  |           \_ ping www.google.ro

那么,为什么进程在脚本中后台执行时ping www.google.ro最终会被继承呢?Systemd PID 1&

答案1

当您在后台启动一个进程(使用&)时,它开始与其父进程同时执行。由于您的脚本没有其他任何事情可做,因此exit孤儿进程被 所采用init。当您不使用 时&,父级wait会等待子级完成,并暂停自身。并且您将脚本视为父脚本。在后一种情况下,家长将显示为暂停/睡眠。

答案2

运行脚本的进程退出,因为它到达了终点脚本的。它到达脚本的末尾,因为该命令是在后台运行的&

相关内容