Bash subshel​​l/pipelines - 哪些部分在子shell中执行?

Jam*_*ley 12 bash

对另一篇文章评论中,@ JonathanLeffler表示:

{...} | somecommand在子shell中运行,不会影响父shell.演示:

man bash

(输出PQR,ABC,PQR三行)

确实:

X=PQR; echo $X; { X=ABC; echo $X; } | cat; echo $X
Run Code Online (Sandbox Code Playgroud)

但是,{ .. }man bash不会在子shell中执行:

james@bodacious-wired:tmp$X=PQR; echo $X; { X=ABC; echo $X; } | cat; echo $X
PQR
ABC
PQR
Run Code Online (Sandbox Code Playgroud)

那么这里发生了什么?是echo $$错?我知道管道的每个部分都在子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. 
Run Code Online (Sandbox Code Playgroud)

编辑添加:

一些人建议$$用来表明事物是(或不是)子壳的一部分.这根本没有用,因为ps在参数扩展阶段会扩展,这在任何命令执行之前很久就会发生.

举个例子:

james@bodacious-wired:tmp$X=PQR; echo $X | sed;  X=ABC; echo $X | sed; echo $X
PQR
ABC
ABC
Run Code Online (Sandbox Code Playgroud)

你可以看到第二次调用7894发生在子shell中,带有pid echo 2$$; 但{ .. }仍然显示bash在变量扩展阶段中替换的值,在它生成子shell之前

为了对比,并表明man bash没有产卵子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$
Run Code Online (Sandbox Code Playgroud)

只是为了证明@nos是正确的,在上面添加一个管道:

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
Run Code Online (Sandbox Code Playgroud)

正如预期的那样,shell产生两个子壳,一个用于管道的每一侧.

nos*_*nos 9

管道的每一侧至少成为子壳.

{ X=ABC; echo $X; }

将制作一个子壳/过程,至少catecho $X.

"管道中的每个命令都作为一个单独的进程执行(即,在子shell中)." ,来自man bash

如果你改为这样做

{ X=SUB ; sleep 1; } &

之后你会看到{ X=SUB ; sleep 1; }显示ABC.

还有其他方法可以在子shell中执行命令,例如,如果你背景子命令:(X=ABC ; echo $X),该组将在子shell中运行,而{ X=ABC; echo $X; }不会.

如果要对始终在子shell中执行的命令进行分组,请使用括号cat而不是大括号.

  • 在`{`之后你需要一个空格,至少在我的'bash`版本中. (2认同)