【问题标题】:Why is Bash handling child processes different compared to Sh为什么 Bash 处理子进程与 Sh 相比不同
【发布时间】:2021-08-21 23:05:36
【问题描述】:

Docker中使用的tiniinit-process提到默认不激活进程组杀,并给出如下示例:

docker run krallin/ubuntu-tini sh -c 'sleep 10'

如果我运行它,然后立即按 Ctrl-C,我确实需要等待 10 秒,直到子进程退出。

但是,如果我使用 bash 而不是 sh

docker run krallin/ubuntu-tini bash -c 'sleep 10'

Ctrl-C,进程立即退出。

为什么sh(符号链接到dash)和bash 对这个子进程的行为不同? 还有Bash是怎么杀掉子进程的,我还以为Bash默认不传播信号呢?

【问题讨论】:

  • 我相信 bash 已优化为在可能的情况下使用 exec 替换自己。在这种情况下,简单的命令sleep 替换了bash。另一方面,dash 可能只是分叉一个新进程并等待它,让它响应信号。
  • 如果是这种情况(很可能),sh -c 'exec sleep 10' 将使行为保持一致。
  • @Peter, btw, bash -c 'sleep 10; exit' 会阻止这种优化:因为sleep 不再是最后一个命令,所以shell 不能再隐含exec

标签: bash docker sh child-process tini


【解决方案1】:

感谢 chepner 和 Charles Duffy 的回答:

bash -c 有一个隐式优化,如果可能,它使用exec 替换自己。 sh (dash) 没有这个优化。另见this observation

验证:

  • 使用bash的进程树:
❯ docker run --name test --rm --detach krallin/ubuntu-tini bash -c 'sleep 60'
03194d48a4dcc8225251fe1e5de2dcbb901c8a9cfd0853ae910bfe4d3735608d
❯ docker exec test ps axfo pid,ppid,args
    PID    PPID COMMAND
      1       0 /usr/bin/tini -- bash -c sleep 60
      7       1 sleep 60
  • 使用sh的进程树:
❯ docker run --name test --rm --detach krallin/ubuntu-tini sh -c 'sleep 60'
e56f207509df4b0b57f8e6b2b2760835f6784a147b200d798dffad112bb11d6a
❯ docker exec test ps axfo pid,ppid,args
    PID    PPID COMMAND
      1       0 /usr/bin/tini -- sh -c sleep 60
      7       1 sh -c sleep 60
      8       7  \_ sleep 60

【讨论】:

  • 干得好。这与我要发布的答案一致,但不记得 Docker 咒语。 (奇怪的是,我无法在没有 Docker 的情况下重现类似的进程树,所以我不知道bashdash 是如何为这个Docker 镜像编译的与我机器上安装的版本或其他版本相比。)
猜你喜欢
  • 1970-01-01
  • 2012-06-18
  • 1970-01-01
  • 2022-06-15
  • 1970-01-01
  • 1970-01-01
  • 2014-12-30
  • 2018-03-19
  • 2014-01-30
相关资源
最近更新 更多