假设我有以下简单的 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
运行脚本的进程退出,因为它到达了终点脚本的。它到达脚本的末尾,因为该命令是在后台运行的&
。