I have some troubles getting a good understanding of the way Bash manages sub-shell creation and the related scoping issues. Hope someone can bring some coherence to my thoughts on this matter.
The first thing I don't get is the way variables are handled in sub-shells. I thought variables weren't inherited, unless they had the eXport flag on. However this doesn't seem to be true for sub-shells created by grouping:
$ n=3
$ ( pstree $$ ; echo $n )
bash---bash---pstree
3
If, instead, I create the sub-shell manually everything goes as expected:
$ export ppid=$$
$ bash
$ pstree $ppid
bash---bash---pstree
$ echo $n
Also some grouping doesn't actually create a sub-shell:
( pstree $$ )
bash---pstree
And some grouping that shouldn't, in fact does:
$ pstree $$ &
[1] 1685
$ bash---pstree
{ pstree $$; } &
[1] 1687
$ bash---bash---pstree
This seems a bit messy to me, with a lot of special cases to keep track of. And it gets more messy. Consider process substitution:
$ cat <(pstree $$)
bash-+-bash---pstree
`-cat
Here, for what is my understanding, bash executed cat in a sub-process, giving it a FIFO to read from. Then forked a sub-shell giving it the other end of the FIFO. The sub-shell ran pstree.
Consider now:
$ pstree $$ > >(cat) # There is some non determinism involved, output may be different
bash---pstree---bash---cat
#or sometimes
bash---pstree---bash
Here bash seems to do something different. It forks a sub-shell, the sub-shell forks another sub-shell, and the situation become: bash---bash(1)---bash(2)
bash(1) (which got the write end of the FIFO) execs pstree and bash(2) (with write end of the FIFO) runs cat in a sub-process.
So in the first case the sub-process gets executed by a sub-shell of the primary shell. In the second by a shell sub-process of the primary command.
In my opinion the 2nd case is because pstree may run before cat is created.
pstree $$ > >(cat)
? – ctrl-alt-delor Feb 09 '20 at 09:58$$
will the not be updated for subshells. Use$BASHPID
instead. – Kusalananda Feb 09 '20 at 10:39> >(...)
, see this. – Feb 09 '20 at 13:14(pwd)
is identical topwd
, because bash optimizes(pwd)
to(exec pwd)
. c) there isn't any grand design principle behind the shell language, its operations grew "organically", and they're not always consistent. – Feb 09 '20 at 13:19