$ p="pineapple" ; echo $p
pineapple
$ (p="peach" ; echo $p)
peach
$ echo $p
pineapple
为什么 shell 自从上次初始化后就不显示 peach 了?括号对这个结果起作用吗?
答案1
是的,这正是括号在类似 Bourne 和类似 csh 的 shell 中的作用:引入一个子 shell 环境(在大多数 shell 中,包括bash
通过分叉子进程来实现),修改被限制在其中。
在该子 shell 环境中对 shell 状态的任何更改,无论是变量、选项、别名、函数、重定向、当前工作目录、信号配置...在离开时都会丢失(恢复)。
运行起来非常有用仅有的不同环境中的一些命令。
例如:
(cd /some/dir && cmd)
cmd
在不同的目录中运行。
或者像这样的事情:
(IFS=:; set -o noglob; ls -l -- $PATH)
我们仅针对 的一次扩展调整 split+glob 运算符$PATH
。
如果您想对命令进行分组而不引入子 shell 环境,请使用{
和}
关键字:
a=1
{ echo "I'm running in the main shell environemnt"; a=2;}
echo "$a"
(echo "I'm running in a subshell environment"; a=3)
echo "$a"
{
请注意 a 后面和;
之前的空格}
,因为它们是由普通字符组成的关键字,而(
和)
是 shell 语法中的特殊字符,此处用于(...)
子 shell 构造。
另请注意,这(...)
不是引入子 shell 环境的唯一构造。还有(在类似 Bourne/Korn 的 shell 中):
- 某些形式的命令替换:
$(subshell)
或`subshell`
- 过程替换:
<(subshell)
,>(subshell)
,=(subshell)
- 管道组件:(
{ subshell; } | othercommand
不是 AT&T ksh 或 zsh 中的最后一个组件)。 - 异步命令:
{ subshell; } &
- 协同处理:
{ subshell; } |&
或coproc { subshell; }
在 POSIX shell 语法中, 和{ ...; }
都(...)
被称为复合命令。两者都可以分配给函数。将函数定义为:
func() (
...
)
代替
func() {
...
}
意味着一旦调用,该函数的主体就会在子 shell 环境中运行,这使得它的行为更像脚本(不同之处在于它仍然继承调用者的所有变量、别名、函数、选项...)。
在fish
外壳中,(...)
是完全不同的东西。这是命令替换,但确实如此不是引入一个子shell环境:
fish> set a 1; echo $a (set a 2; echo $a) $a
1 2 2
它类似于${ ...; }
ksh93 或 mksh shell 的命令替换形式,也不会引入子 shell 环境。