Search code examples
bashdockershchild-processtini

Why is Bash handling child processes different compared to Sh


The tini init-process, used in Docker, mentions that process group killing is not activated by default and gives the following example:

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

If I run this, and press Ctrl-C immediately after, I indeed have to wait for 10 seconds till the child process exits.

However, if instead of sh I used bash:

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

and press Ctrl-C, the process exits immediately.

Why do sh (which is symlinked to dash) and bash behave differently towards this child process? And how does Bash kill the child process, I thought Bash does not propagate signals by default?


Solution

  • Answered thanks to chepner and Charles Duffy:

    bash -c has an implicit optimization where it uses exec to replace itself if possible. sh (dash) does not have this optimization. See also this observation.

    To verify:

    • Process tree using 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
    
    • Process tree using 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