Igo*_*rio 126 bash shell-script subshell
根据我的阅读,将命令放在括号中应该在子shell 中运行它,类似于运行脚本。如果这是真的,如果 x 未导出,它如何查看变量 x?
x=1
Run Code Online (Sandbox Code Playgroud)
(echo $x)在命令行上运行结果为 1
echo $x正如预期的那样,在脚本中运行不会产生任何结果
Gil*_*il' 169
子shell 开始时是原始shell 进程的几乎相同的副本。在幕后,shell 调用fork系统调用1,这会创建一个新进程,其代码和内存是副本2。创建子外壳时,它与其父外壳之间几乎没有区别。特别是,它们具有相同的变量。即使是$$特殊变量在子 shell 中也保持相同的值:它是原始 shell 的进程 ID。同样$PPID是原始 shell 的父级的 PID。
一些shell 更改了子shell 中的一些变量。Bash 设置BASHPID为 shell 进程的 PID,它在子 shell 中发生变化。Bash、zsh 和 mksh 安排$RANDOM在父 shell 和子 shell 中产生不同的值。但除了这些内置的特殊情况外,所有变量在子 shell 中的值与原始 shell 中的值相同,导出状态相同,只读状态相同,等等。所有函数定义、别名定义、shell 选项和其他设置也会被继承。
创建的子shell(…)与其创建者具有相同的文件描述符。其他一些创建子shell的方法在执行用户代码之前修改了一些文件描述符;例如,管道的左侧在子壳3 中运行,标准输出连接到管道。子shell也以相同的当前目录、相同的信号掩码等开始。少数例外之一是子shell不继承自定义陷阱:被忽略的信号( )在子shell中仍然被忽略,但其他陷阱( SIGNAL )被重置到默认动作4。trap '' SIGNALtrap CODE
因此,子shell 与执行脚本不同。脚本是一个单独的程序。巧合的是,这个单独的程序可能也是由与父程序相同的解释器执行的脚本,但这种巧合并没有使单独的程序对父程序的内部数据有任何特殊的可见性。未导出的变量是内部数据,所以当子shell 脚本的解释器被执行时,它看不到这些变量。导出的变量,即环境变量,被传送到执行的程序。
因此:
x=1
(echo $x)
Run Code Online (Sandbox Code Playgroud)
打印1是因为子外壳是产生它的外壳的复制品。
x=1
sh -c 'echo $x'
Run Code Online (Sandbox Code Playgroud)
恰巧运行shell作为外壳的子过程,但x在第二行有与没有更多的连接x,第二行比
x=1
perl -le 'print $x'
Run Code Online (Sandbox Code Playgroud)
或者
x=1
python -c 'print x'
Run Code Online (Sandbox Code Playgroud)
1 一个例外是ksh93分叉被优化出来并且其大部分副作用被模拟的外壳。
2 从 语义上讲,它们是副本。从实施的角度来看,有很多共享正在进行。
3 对于右侧,它取决于外壳。
4 如果您对此进行测试,请注意,诸如此类的内容$(trap)可能会报告原始 shell 的陷阱。还要注意,许多 shell 在涉及陷阱的极端情况下都有错误。例如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陷阱到所有子外壳,但中间子外壳被优化掉了,所以没有运行它的ERR陷阱。
Mik*_*kel 18
显然,是的,正如所有文档所说,括号中的命令在子shell 中运行。
子shell 继承了所有父变量的副本。不同之处在于您在子 shell 中所做的任何更改也不会在父级中进行。
ksh 手册页比 bash 手册页更清楚一点:
man ksh:带括号的命令在子 shell 中执行,而不删除非导出的变量。
man bash:
(列表)list 在子 shell 环境中执行(请参阅下面的命令执行环境)。影响 shell 环境的变量赋值和内置命令在命令完成后不再有效。
命令执行环境
shell 有一个执行环境,它包括以下内容: [...] 通过变量赋值设置的 shell 参数 [...]。
命令替换、用括号分组的命令和异步命令在与 shell 环境相同的子 shell 环境中调用,[...]