$ sudo strace -f -e trace=process -p 6913
Process 6913 attached
clone(Process 12931 attached
child_stack=0, flags=CLONE_CHILD_CLEARTID|CLONE_CHILD_SETTID|SIGCHLD, child_tidptr=0x7f457c05ca10) = 12931
[pid 12931] execve("/bin/date", ["date"], [/* 66 vars */]) = 0
[pid 12931] arch_prctl(ARCH_SET_FS, 0x7f530c5ee740) = 0
[pid 12931] exit_group(0) = ?
[pid 12931] +++ exited with 0 +++
--- SIGCHLD {si_signo=SIGCHLD, si_code=CLD_EXITED, si_pid=12931, si_status=0, si_utime=0, si_stime=0} ---
wait4(-1, [{WIFEXITED(s) && WEXITSTATUS(s) == 0}], WNOHANG|WSTOPPED|WCONTINUED, NULL) = 12931
wait4(-1, 0x7ffea6780718, WNOHANG|WSTOPPED|WCONTINUED, NULL) = -1 ECHILD (No child processes)
When running echo $b &, the output of tracing the first shell 6913 in the second shell is:
$ sudo strace -f -e trace=process -p 6913
Process 6913 attached
clone(Process 31319 attached
child_stack=0, flags=CLONE_CHILD_CLEARTID|CLONE_CHILD_SETTID|SIGCHLD, child_tidptr=0x7f457c05ca10) = 31319
[pid 31319] exit_group(0) = ?
[pid 31319] +++ exited with 0 +++
--- SIGCHLD {si_signo=SIGCHLD, si_code=CLD_EXITED, si_pid=31319, si_status=0, si_utime=0, si_stime=0} ---
wait4(-1, [{WIFEXITED(s) && WEXITSTATUS(s) == 0}], WNOHANG|WSTOPPED|WCONTINUED, NULL) = 31319
wait4(-1, 0x7ffea6780718, WNOHANG|WSTOPPED|WCONTINUED, NULL) = -1 ECHILD (No child processes)
When running { date; } &, the output of tracing the first shell 6913 in the second shell is:
$ sudo strace -f -e trace=process -p 6913
Process 6913 attached
clone(child_stack=0, flags=CLONE_CHILD_CLEARTID|CLONE_CHILD_SETTID|SIGCHLD, child_tidptr=0x7f457c05ca10) = 31294
Process 31294 attached
[pid 31294] clone(Process 31295 attached
child_stack=0, flags=CLONE_CHILD_CLEARTID|CLONE_CHILD_SETTID|SIGCHLD, child_tidptr=0x7f457c05ca10) = 31295
[pid 31294] wait4(-1, <unfinished ...>
[pid 31295] execve("/bin/date", ["date"], [/* 67 vars */]) = 0
[pid 31295] arch_prctl(ARCH_SET_FS, 0x7f78b7f0b740) = 0
[pid 31295] exit_group(0) = ?
[pid 31295] +++ exited with 0 +++
[pid 31294] <... wait4 resumed> [{WIFEXITED(s) && WEXITSTATUS(s) == 0}], 0, NULL) = 31295
[pid 31294] --- SIGCHLD {si_signo=SIGCHLD, si_code=CLD_EXITED, si_pid=31295, si_status=0, si_utime=0, si_stime=0} ---
[pid 31294] wait4(-1, 0x7ffea67811d8, WNOHANG, NULL) = -1 ECHILD (No child processes)
[pid 31294] exit_group(0) = ?
[pid 31294] +++ exited with 0 +++
--- SIGCHLD {si_signo=SIGCHLD, si_code=CLD_EXITED, si_pid=31294, si_status=0, si_utime=0, si_stime=0} ---
wait4(-1, [{WIFEXITED(s) && WEXITSTATUS(s) == 0}], WNOHANG|WSTOPPED|WCONTINUED, NULL) = 31294
wait4(-1, 0x7ffea6780718, WNOHANG|WSTOPPED|WCONTINUED, NULL) = -1 ECHILD (No child processes)
As far as running the command date is concerned, directly running it and running it in background seem to do the same
thing:
When running the command directly, the original bash shell 6913
clone() itself, and then its clone 12918 execve() the command.
When running the command in background, the original bash shell 6913
clone() itself, and then its clone 12931 execve() the command.
What are the differences between them?
It is said that a command running in background can access a local
variable in the parent shell, because it runs in a subshell of the
parent shell, while a command running directly can't, because it doesn't run in a subshell of the parent shell. Can we
explain the difference using the outputs of tracing?
As far as running the command date is concerned, directly running it and running it in background seem to do the same
thing:
When running the command directly, the original bash shell 6913
clone() itself, and then its clone 12918 execve() the command.
When running the command in background, the original bash shell 6913
clone() itself, and then its clone 12931 execve() the command.
Both calls clone() only once. What are the differences between them?
It doesn't matter the command is external or builtin, for example, running date& and running echo $b & both call clone() once. Why is such a difference?
Compare running date & and { date; } &. The Bash Manual says
braces don't create subshell. Why are their tracing outputs
different:
- in the tracing output of
date&, there is only one clone (6913 clone() to create 12931) and the clone 12931 execve() date,
- in the tracing output of
{ date; }&, there are two clones (6913 clone() to create 31294, and 31294 clone() to create 31295) and
the last clone 31295 execve() date
It is said that a command running in background (e.g. date&) can access a local
variable in the parent shell, because it runs in a subshell of the
parent shell, while a command running directly can't (e.g. date), because it doesn't run in a subshell of the parent shell. Can we
explain the difference using the outputs of tracing?
$ b=1
$ { echo $b; } &
[1] 31214
1
Here b is variable local to the parent shell, and not an environment variable. The subshell created by & copies b from the parent shell, so b is echoed with 1 the value from the parent shell. I created this example, from another one which uses command substitution instead of background, which both create a subshell to run a command.