Appearance
Subshell
Subshell(子 Shell)是在当前 Shell 进程中创建的一个子进程,继承父 Shell 的环境但在独立的空间中运行。
什么是 Subshell
bash
# 使用括号创建 subshell
(
echo "子 shell 中的 PID:$BASHPID"
cd /tmp
VAR="在子 shell 中"
)
echo "父 shell 中的 PID:$BASHPID"
echo "当前目录:$(pwd)" # 仍在原目录,cd 不影响父 shell
echo "VAR:$VAR" # 空,子 shell 的变量不影响父 shell创建 Subshell 的方式
1. 括号 ( )
bash
(命令1; 命令2; 命令3)
# 示例
(cd /tmp; ls; pwd)
echo "父 shell 目录:$(pwd)" # 不变2. 命令替换 $( )
bash
output=$(cd /tmp && ls)
echo "$output"3. 管道
bash
# 管道两侧的命令都在 subshell 中运行
echo "hello" | read line # 不推荐,read 在 subshell 中,变量丢失
echo "hello" | { read line; echo "读取:$line"; } # 同一 subshell4. 进程替换 <( ) 和 >( )
bash
# 将命令输出作为文件输入
diff <(ls dir1) <(ls dir2)
# 将输出重定向到命令
tee >(gzip > output.gz) > output.txtSubshell 的特性
继承父 Shell 的变量
bash
PARENT_VAR="来自父 shell"
(
echo "$PARENT_VAR" # 可以读取父 shell 变量
PARENT_VAR="在子 shell 中修改"
echo "$PARENT_VAR" # 显示修改后的值
)
echo "$PARENT_VAR" # 仍是"来自父 shell",子 shell 修改不影响父 shell继承函数和别名
bash
greet() { echo "Hello, $1!"; }
(
greet "World" # 可以调用父 shell 定义的函数
)独立的工作目录
bash
(cd /tmp; pwd) # 输出 /tmp
pwd # 输出原目录Subshell 的用途
临时改变环境
bash
#!/bin/bash
# 在子 shell 中设置不同的 IFS,不影响外部
(
IFS=:
for part in $PATH; do
echo "$part"
done
)
echo "IFS 恢复了:'$IFS'"隔离错误
bash
#!/bin/bash
# 子 shell 中的 exit 不会终止父 shell
(
echo "进入子 shell"
exit 1
echo "这行不会执行"
)
echo "父 shell 继续运行,子 shell 退出码:$?"并行执行
bash
#!/bin/bash
# 在 subshell 中并行执行任务
(sleep 2; echo "任务 1 完成") &
(sleep 1; echo "任务 2 完成") &
(sleep 3; echo "任务 3 完成") &
wait
echo "所有任务完成"分组重定向
bash
#!/bin/bash
# 将多个命令的输出重定向到同一个文件
(
echo "=== 系统信息 ==="
uname -a
echo "=== 磁盘使用 ==="
df -h
echo "=== 内存使用 ==="
free -h
) > system_report.txtSubshell vs 函数
| 特性 | Subshell ( ) | 函数 |
|---|---|---|
| 变量隔离 | 是 | 否(除非 local) |
| 目录隔离 | 是 | 否 |
| exit 行为 | 只退出子 shell | 退出整个脚本 |
| 性能 | 较低(fork 进程) | 较高 |
| 使用场景 | 需要隔离时 | 代码复用 |
$BASH_SUBSHELL 变量
bash
echo "父 shell 层级:$BASH_SUBSHELL" # 0
(
echo "第 1 层 subshell:$BASH_SUBSHELL" # 1
(
echo "第 2 层 subshell:$BASH_SUBSHELL" # 2
)
)注意事项
bash
#!/bin/bash
# 管道中的变量问题
count=0
cat file.txt | while read line; do
(( count++ )) # count 在 subshell 中修改,外部看不到
done
echo "count: $count" # 0!
# 解决方案:使用进程替换
count=0
while read line; do
(( count++ ))
done < <(cat file.txt)
echo "count: $count" # 正确的行数