Answers:
子外壳程序开始时与原始外壳程序过程几乎完全相同。在后台,shell调用fork
系统调用1,这将创建一个新进程,其代码和内存为副本2。创建子Shell时,它与它的父级之间几乎没有区别。特别是,它们具有相同的变量。甚至$$
特殊变量在子Shell中也保持相同的值:它是原始Shell的进程ID。同样$PPID
,原始外壳的父代的PID也是如此。
一些外壳程序会更改子外壳程序中的一些变量。Bash设置BASHPID
为Shell进程的PID,该PID在子Shell中更改。Bash,zsh和mksh安排$RANDOM
在父级和子shell中产生不同的值。但是,除了诸如此类的内置特殊情况外,所有变量在子Shell中的值与原始Shell中的值相同,具有相同的导出状态,相同的只读状态等。所有函数定义,别名定义,Shell选项和其他设置也将被继承。
由创建的子Shell (…)
具有与其创建者相同的文件描述符。创建子外壳的其他一些方法在执行用户代码之前会修改一些文件描述符。例如,管道的左侧在子壳体3中延伸,标准输出连接到该管道。子外壳程序也以相同的当前目录,相同的信号掩码等开始。少数例外之一是子外壳程序不继承自定义陷阱:被忽略的信号()在子外壳程序中仍然被忽略,但其他陷阱(SIGNAL)被重置采取默认操作4。trap '' SIGNAL
trap CODE
因此,子shell与执行脚本不同。脚本是一个单独的程序。该单独的程序也可能恰巧也是由与父程序相同的解释器执行的脚本,但是这种巧合不会使单独的程序对父级的内部数据有任何特殊的可见性。非导出变量是内部数据,因此当执行子外壳脚本的解释器时,看不到这些变量。导出的变量(即环境变量)被传输到执行的程序。
从而:
x=1
(echo $x)
进行打印,1
因为子外壳是生成它的外壳的复制。
x=1
sh -c 'echo $x'
碰巧在外壳程序的子进程中运行外壳程序,但是x
第二行上的与第二行上的连接没有x
比
x=1
perl -le 'print $x'
要么
x=1
python -c 'print x'
1 一个例外是ksh93
外壳,在该外壳上优化了分叉并且可以模拟其大多数副作用。
2从 语义上讲,它们是副本。从实现的角度来看,正在进行很多共享。
3 对于右侧,取决于外壳。
4 如果您对此进行测试,请注意,诸如此类的内容$(trap)
可能会报告原始外壳程序的陷阱。还要注意,许多壳在涉及陷阱的极端情况下都有错误。例如,ninjalj指出,从bash 4.3开始,在“两个子外壳”的情况下,从嵌套子外壳bash -x -c 'trap "echo ERR at \$BASH_SUBSHELL \$BASHPID" ERR; set -E; false; echo one subshell; (false); echo two subshells; ( (false) )'
运行ERR
陷阱,但不ERR
从中间子外壳运行陷阱- set -E
选项应传播ERR
陷阱到所有子shell,但是中间子shell已被优化,因此无法运行其ERR
陷阱。
echo $(x=2; echo $x)
,片段$(x=2; echo $x)
需要扩展。这需要评估命令x=2; echo $x
。$x
在评估零件之后,在此评估期间发生扩展x=2
。
x
设置)echo $(echo foo >somefile)${x-$(cat somefile)}
或,顺序就很重要echo $(echo $x),${x=1}
。
./file
不在子shell中执行。另请参见unix.stackexchange.com/q/261638和unix.stackexchange.com/a/157962
显然,是的,正如所有文档所述,带括号的命令在子外壳中运行。
子外壳程序继承了所有父变量的副本。不同之处在于您在子Shell中所做的任何更改都不会在父级中进行。
ksh手册页比bash手册页更加清晰:
man ksh
:在子外壳中执行带括号的命令,而不会删除未导出的变量。
man bash
:
(
清单)
该列表在子外壳程序环境中执行(请参见下面的“命令执行环境”)。在命令完成后,影响外壳环境的变量分配和内置命令将保持无效。
命令执行环境
外壳程序具有执行环境,该环境包括以下内容:外壳程序参数,这些变量是通过变量赋值设置的。
在子shell环境中调用命令替换,用括号分组的命令以及异步命令,该子shell环境是shell环境的副本,[...]
When a simple command other than a builtin or shell function is to be executed, it is invoked in a separate execution environment that consists of the following.
,后者包含项:(· shell variables and functions marked for export, along with variables exported for the command, passed in the environment
来自同man bash
一部分),该项解释了为什么echo $x
-script如果x
不导出则什么也不打印。
x=out; (x=in; echo $x)
)