()启动子Shell,变量和目录变更不透出;{}在当前Shell执行,变量修改立即生效。二者核心区别在于是否创建新进程:前者隔离环境,后者延续上下文。

子Shell和当前Shell环境的区分,核心就在圆括号 () 和大括号 {} 的行为差异:前者启动新进程(隔离变量、工作目录等),后者在原进程内执行(变量修改会生效)。
() 启动子Shell,变量不透出
用 () 包裹的命令会在一个独立的子Shell中运行,它的所有变更——包括变量赋值、cd切换目录、umask设置等——都只在该子Shell内部有效,退出后自动丢弃。
- 变量修改不影响父Shell:
var=old; (var=new; echo $var); echo $var输出new再输出old - 目录切换不保留:
(cd /tmp; pwd); pwd第二行仍显示原路径 - 命令间用分号或换行分隔,括号与命令间无需空格,末尾分号可省略
{} 在当前Shell执行,变量可延续
{} 不创建新进程,只是将多个命令逻辑分组,在当前Shell上下文中顺序执行。因此所有副作用都会保留在当前环境中。
- 变量赋值立即生效:
var=old; { var=new; echo $var; }; echo $var两次都输出new - 必须注意语法细节:左花括号
{后需跟空格;命令间用分号分隔;最后一个命令后必须加分号 - 重定向若写在
{}外部(如{ cmd1; cmd2; } >out.txt),则整个块的输出被统一重定向
常见误用与典型场景
混淆两者最常导致“变量设了却没用上”或“cd进去了却还在原目录”。实际使用中:
- 需要临时修改环境又不想影响后续逻辑 → 用
(),比如测试不同PATH下的命令行为 - 批量执行多步操作且依赖前步结果(如连续设置几个变量再一起用)→ 用
{} - 管道前加
{}可让多条命令共享输入流:echo "a b c" | { read x y z; echo "got: $x $y $z"; } - 数组初始化、命令替换、函数定义等不涉及环境隔离的场景,不用
()或{},避免无谓开销
一句话记住关键区别
() 是“开个新窗口干活,关掉就清空”;{} 是“在同一窗口里连贯操作,做完还在原地”。选哪个,取决于你是否希望改动延续到后续代码。

















