When will bash -c lead to the creation of a child shell?

on my centos7.4 server if you run

bash -c "python -m SimpleHTTPServer"

pstree -sp 10784 (PID of python server)

will show

systemd(1)───sshd(922)───sshd(11595)───sshd(11597)───bash(11598)───python(11617)

and

bash -c "python -V && python -m SimpleHTTPServer"

I got

systemd(1)───sshd(922)───sshd(11595)───sshd(11597)───bash(11598)───bash(11638)───python(11640)

So why is the child shell created in the second command?

+4
source share
3 answers

The second command uses a subshell to process the statement &&— it needs to wait for SIGCHLD to complete to complete the first command, and then decide whether the second command should be executed.

In the first case, this happens: Bash starts up and sees that it needs to run a simple line. As an optimization, it is then execthat the command is not forked first, and the sub-community is replaced with the python command.

, bash forks python -V . SIGCHLD , ( fork)

. 1370

+4

bash -c . , , python execve():

bash (execve python - m SimpleHTTPServer)

strace:

$ strace -e clone,fork,vfork,execve -f bash -c "python2 -m SimpleHTTPServer"
execve("/bin/bash", ["bash", "-c", "python2 -m SimpleHTTPServer"], [/* 71 vars */]) = 0
execve("/usr/bin/python2", ["python2", "-m", "SimpleHTTPServer"], [/* 71 vars */]) = 0
Serving HTTP on 0.0.0.0 port 8000 ...

: , . - :

       +-- execve python -V
bash --+
       +-- execve python -m SimpleHTTPServer

bash fork() execve() , :

$ strace -e clone,fork,vfork,execve -f bash -c "python2 -V && python2 -m SimpleHTTPServer"
execve("/bin/bash", ["bash", "-c", "python2 -V && python2 -m SimpleH"...], [/* 71 vars */]) = 0
clone(child_stack=0, flags=CLONE_CHILD_CLEARTID|CLONE_CHILD_SETTID|SIGCHLD, child_tidptr=0x7ff72d3049d0) = 8631
Process 8631 attached
[pid  8631] execve("/usr/bin/python2", ["python2", "-V"], [/* 71 vars */]) = 0
Python 2.7.5
[pid  8631] +++ exited with 0 +++
--- SIGCHLD {si_signo=SIGCHLD, si_code=CLD_EXITED, si_pid=8631, si_status=0, si_utime=0, si_stime=0} ---
clone(child_stack=0, flags=CLONE_CHILD_CLEARTID|CLONE_CHILD_SETTID|SIGCHLD, child_tidptr=0x7ff72d3049d0) = 8632
Process 8632 attached
[pid  8632] execve("/usr/bin/python2", ["python2", "-m", "SimpleHTTPServer"], [/* 71 vars */]) = 0
Serving HTTP on 0.0.0.0 port 8000 ...

, . zsh execve() python -m simpleHTTPServer , :

zsh (waits for subcommand, then execve python -m sim...) --- execve python -V

strace:

$ strace -e clone,fork,vfork,execve -f zsh -c "python2 -V && python2 -m SimpleHTTPServer"
execve("/bin/zsh", ["zsh", "-c", "python2 -V && python2 -m SimpleH"...], [/* 71 vars */]) = 0
clone(child_stack=0, flags=CLONE_CHILD_CLEARTID|CLONE_CHILD_SETTID|SIGCHLD, child_tidptr=0x7f1c5c60a9d0) = 8670
Process 8670 attached
[pid  8670] execve("/usr/bin/python2", ["python2", "-V"], [/* 72 vars */]) = 0
Python 2.7.5
[pid  8670] +++ exited with 0 +++
--- SIGCHLD {si_signo=SIGCHLD, si_code=CLD_EXITED, si_pid=8670, si_status=0, si_utime=0, si_stime=0} ---
execve("/usr/bin/python2", ["python2", "-m", "SimpleHTTPServer"], [/* 72 vars */]) = 0
Serving HTTP on 0.0.0.0 port 8000 ...
+2

bash -c "python -m SimpleHTTPServer"  

bash , python -m SimpleHTTPServer - , bash.

  • python -m SimpleHTTPServer - , , bash bash -c.
  • python -m SimpleHTTPServer ( ), bash fork (python).
  • python -m SimpleHTTPServer exec.

bash -c "python -V && python -m SimpleHTTPServer"  

python -V bash , fork, exec.

  • bash fork (bash) bash -c.
  • python -V - ( ), fork (python).
  • python -V exec.
  • After executing the python -Vfull parent shell, there will again be a forknew child process ( python) for the external command python -m SimpleHTTPServer.
  • the child process will execute python -m SimpleHTTPServerwith exec.

A simple example would be

$ pstree $$
bash---pstree
$ ( pstree $$ )
bash---pstree
$ ( pstree $$ ; echo)
bash---bash---pstree 

Recommended reading: Why (...) does not spawn a new child process when launched in the background?

0
source

Source: https://habr.com/ru/post/1695702/


All Articles