对于Bash管理子shell创建的方式和相关的范围问题,我有一些困难。希望有人能给我在这件事上的想法带来一些连贯性。
首先,我不明白在子shell中处理变量的方式。我认为变量不是遗传的,除非它们有eXport标志。但是,对于通过分组创建的子shell,情况似乎并非如此:
$ n=3
$ ( pstree $ ; echo $n )
bash---bash---pstree
3相反,如果我手动创建子shell,那么所有的事情都会如期而至:
$ export ppid=$
$ bash
$ pstree $ppid
bash---bash---pstree
$ echo $n另外,一些分组实际上并不会创建一个子shell:
( pstree $ )
bash---pstree事实上,一些不应该这样做的分组:
$ pstree $ &
[1] 1685
$ bash---pstree
{ pstree $; } &
[1] 1687
$ bash---bash---pstree对我来说,这似乎有点混乱,有很多特殊的情况需要注意。而且会变得更乱。考虑进程替代:
$ cat <(pstree $)
bash-+-bash---pstree
`-cat在这里,我的理解是,bash在一个子进程中执行cat,给它一个FIFO来读取。然后分叉子壳,使它的另一端先进先出。那副炮弹跑了。
现在考虑:
$ pstree $ > >(cat) # There is some non determinism involved, output may be different
bash---pstree---bash---cat
#or sometimes
bash---pstree---bash在这里,巴什似乎做了一些不同的事情。它分叉一个子壳,子壳分叉另一个子壳,情况变成:bash-bash(1)-bash(2)
bash(1) (它得到FIFO的写端)、执行部分和bash(2) (具有FIFO的写端)在子进程中运行cat。
因此,在第一种情况下,子进程由主shell的子shell执行。在第二个由shell子进程的主命令。
在我看来,第二种情况是因为pstree可能在创建cat之前运行。
发布于 2020-02-09 09:57:37
我会尽量涵盖其中的大部分内容。
当您执行子shell (),$(),<():bash将调用fork()。这将创建一个新的子进程,即与父进程相同的 <#>exactly,除了pid、ppid和返回叉的值(子进程为0;父进程为正pid;父进程为负--没有创建子进程)。因此,子shell将具有相同的状态/相同的变量。
当您调用bash时,shell将调用fork(),然后调用exec("bash") (实际上是变体之一)。这将用一个新映像替换克隆的bash,该映像从一开始就开始运行。因此,变量被清除,配置文件被重新读取.
当您使用&时。Bash调用fork()到后台的进程。它似乎比需要的要多分叉一次,但很可能是使用分叉式的bash来帮助管理工作。(为什么叉子不便宜呢?)
对于最后一个案例,pstree $ > >(cat)。(这花了我更长的时间来完成):像往常一样,Bash叉可以运行一个新的过程。在调用exec之前,它需要重定向stdin/out/err (在本例中只是stdout)。在这样做的过程中,它必须在子shell中运行cat,它也是这样做的。现在,cat是新的bash的孩子。新来的是老一辈的孩子。接下来,新bash调用exec,并成为pstree。
https://unix.stackexchange.com/questions/566551
复制相似问题