【发布时间】:2012-02-02 08:47:27
【问题描述】:
@JonathanLeffler 在comment on another post 中表示:
{ ... } | somecommand 在子 shell 中运行,不影响 父壳。演示:
X=PQR; echo $X; { X=ABC; echo $X; } | cat; echo $X(三行输出 PQR、ABC、PQR)
确实:
james@bodacious-wired:tmp$X=PQR; echo $X; { X=ABC; echo $X; } | cat; echo $X
PQR
ABC
PQR
但是,man bash 表示 { .. } 不在子 shell 中执行:
{ list; }
list is simply executed in the current shell environment. list must be
terminated with a newline or semicolon. This is known as a group command.
那么这里发生了什么? man bash 错了吗?我知道管道的每个部分都在子shell中执行;但我不明白这是如何导致观察到的行为的。例如:
james@bodacious-wired:tmp$X=PQR; echo $X | sed; X=ABC; echo $X | sed; echo $X
PQR
ABC
ABC
编辑添加:
一些人建议使用echo $$ 来表明事物是(或不是)子shell 的一部分。这一点用处都没有,因为$$ 在参数扩展阶段会被扩展,这在任何命令执行之前很久就发生了。
举个例子:
james@bodacious-wired:tmp$echo 1$$; ps; ( echo 2$$; ps ); echo 3$$; ps
11194
PID TTY TIME CMD
1194 ttys000 0:00.22 -bash
21194
PID TTY TIME CMD
1194 ttys000 0:00.22 -bash
7894 ttys000 0:00.00 -bash
31194
PID TTY TIME CMD
1194 ttys000 0:00.22 -bash
james@bodacious-wired:tmp$
您可以看到ps 的第二次调用发生在子shell 中,pid 为7894;但是echo 2$$ 仍然显示 bash 在变量扩展阶段替换的值,在它产生子shell之前
为了对比,并证明{ .. } 确实没有生成子shell:
james@bodacious-wired:tmp$echo 1$$; ps; { echo 2$$; ps; }; echo 3$$; ps
11194
PID TTY TIME CMD
1194 ttys000 0:00.22 -bash
21194
PID TTY TIME CMD
1194 ttys000 0:00.22 -bash
31194
PID TTY TIME CMD
1194 ttys000 0:00.23 -bash
只是为了证明@nos是正确的,在上面加一个管道:
james@bodacious-wired:tmp$echo 1$$; ps; { echo 2$$; ps; } | sed ; echo 3$$; ps
11194
PID TTY TIME CMD
1194 ttys000 0:00.25 -bash
21194
PID TTY TIME CMD
1194 ttys000 0:00.25 -bash
7945 ttys000 0:00.00 -bash
7946 ttys000 0:00.00 sed
31194
PID TTY TIME CMD
1194 ttys000 0:00.25 -bash
正如预期的那样,shell 生成了两个子shell,一个用于管道的每一侧。
【问题讨论】:
标签: bash