Bash子shell/管道-哪些部分在子shell中执行?
在一份声明中,@JonathanLeffler说: {…}| somecommand在子shell中运行,不会影响 父shell。演示:Bash子shell/管道-哪些部分在子shell中执行?,bash,Bash,在一份声明中,@JonathanLeffler说: {…}| somecommand在子shell中运行,不会影响 父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 但是,manbash表示,
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
但是,manbash
表示,{..}
不会在子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.
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
这是怎么回事?manbash
错了吗?我知道管道的每个部分都在子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中,pid7894
;但是echo2$$
仍然显示bash在生成子shell之前在变量扩展阶段替换的值
作为对比,并演示{..}
不会生成子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.
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,管道的每侧各有一个子shell。实际上,大括号是在一个新的子shell中执行的,,但只有在管道化时才执行。第一个命令带有
cat
,第二个命令不带:
xxx@yyy:~$ ps; X=PQR; echo $X; { ps; X=ABC; echo $X; } | cat; ps; echo $X
PID TTY TIME CMD
6768 pts/7 00:00:00 bash
13158 pts/7 00:00:00 ps
PQR
PID TTY TIME CMD
6768 pts/7 00:00:00 bash
13159 pts/7 00:00:00 bash
13160 pts/7 00:00:00 cat
13161 pts/7 00:00:00 ps
ABC
PID TTY TIME CMD
6768 pts/7 00:00:00 bash
13162 pts/7 00:00:00 ps
PQR
xxx@yyy:~$ ps; X=PQR; echo $X; { ps; X=ABC; echo $X; }; ps; echo $X
PID TTY TIME CMD
6768 pts/7 00:00:00 bash
13239 pts/7 00:00:00 ps
PQR
PID TTY TIME CMD
6768 pts/7 00:00:00 bash
13240 pts/7 00:00:00 ps
ABC
PID TTY TIME CMD
6768 pts/7 00:00:00 bash
13245 pts/7 00:00:00 ps
ABC
在这种情况下,6768
是终端外壳的PID,13159
是为支架启动的子外壳的PID
似乎当(且仅当)管道化时,
{}
在子shell中执行。管道的每一侧至少成为子shell
X=PQR; echo $X; { X=ABC; echo $X; } | cat; echo $X
将生成至少{X=ABC;echo$X;}
和cat
的子shell/进程
“管道中的每个命令都作为单独的进程执行(即,在子shell中)。”,来自ManBash
如果你改为这样做
X=PQR; echo $X; { X=ABC; echo $X; } ; echo | cat; echo $X
之后您将看到,echo$X
显示ABC
在子shell中执行命令还有其他方式,例如,如果您将子命令设置为背景:{X=SUB;sleep 1;}&
,则该组将在子shell中运行,而仅{X=SUB;sleep 1;}
不会
如果您想对总是在子shell中执行的命令进行分组,请使用括号,而不是大括号。我想我们赢了。创建子shell的不是
{..}
,而是管道。实际上,我一开始就直截了当地说了。在{
之后需要一个空格,至少在我的bash
$(cmd args)版本中,构造还需要创建一个子shell:echo$(echo$bash\u subshell)
管道创建子shell,而不是大括号。不,不是管道,而是与管道连接的大括号。检查ps
vs.ps | cat
vs.{ps;}cat
的输出。大括号从不调用子shell!只有管道才会这样做: