2012-02-02 7 views
12

En un comment on another post, @JonathanLeffler declaró que:Subshell/pipes de Bash: ¿qué partes se están ejecutando en subshells?

{...} | somecommand se ejecuta en un subconjunto y no afecta al shell primario . Demostración:

X=PQR; echo $X; { X=ABC; echo $X; } | cat; echo $X

(con salida de PQR, ABC, PQR en tres líneas)

y de hecho:

[email protected]:tmp$X=PQR; echo $X; { X=ABC; echo $X; } | cat; echo $X 
PQR 
ABC 
PQR 

Sin embargo, man bash dice que { .. } hace no ejecutar en una subshell:

{ 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. 

¿Qué está pasando aquí? ¿Está equivocado man bash? Sé que cada parte de una tubería se ejecuta en una subcapa; pero no veo cómo eso causa el comportamiento observado. Por ejemplo:

[email protected]:tmp$X=PQR; echo $X | sed; X=ABC; echo $X | sed; echo $X 
PQR 
ABC 
ABC 

Editado para añadir:

Algunas personas han sugerido el uso de echo $$ para mostrar que las cosas son (o no son) partes de un subnivel. Esto no es del todo útil, ya que el $$ se expande durante la etapa de expansión de parámetros, que ocurre mucho antes de que se ejecuten los comandos.

A modo de ejemplo:

[email protected]: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 
[email protected]:tmp$ 

se puede ver que la segunda invocación de ps ocurrió dentro de un subnivel, con pid 7894; pero echo 2$$ todavía muestra el valor que Bash sustituido en la fase de expansión de variables, antes de que dio lugar a la subcapa

Por el contrario, y demostrando que { .. } hace no generar una subcapa:

[email protected]: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 

Sólo para demostrar que @nos es correcta, añadir una tubería de lo anterior:

[email protected]: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 

Como era de esperar, la cáscara desova dos subcapas, una para cada lado de la tubería.

Respuesta

9

Cada lado de una tubería se convierte en una subcategoría como mínimo.

X=PQR; echo $X; { X=ABC; echo $X; } | cat; echo $X

hará un subnivel/proceso de, al menos { X=ABC; echo $X; } y cat.

"Cada comando en una canalización se ejecuta como un proceso separado (es decir, en una subcadena)." , A partir de bash

Si en lugar de hacer esto

X=PQR; echo $X; { X=ABC; echo $X; } ; echo | cat; echo $X

Usted verá más tarde que echo $X muestra ABC.

Hay otras maneras en que los comandos se ejecutan también en subcapas, p. si tiene un subcomando en segundo plano: { X=SUB ; sleep 1; } &, ese grupo se ejecutará en una subcadena, mientras que solo { X=SUB ; sleep 1; } no lo hará.

Si desea agrupar comandos que siempre se ejecutan en una subshell, use paréntesis, (X=ABC ; echo $X) en lugar de llaves.

+1

Creo que tenemos un ganador. No es '{..}' que está creando la subshell, es la tubería. Prácticamente salí y dije eso desde el principio. –

+2

Necesitas un espacio después del '{', al menos en mi versión de 'bash'. – krlmlr

+1

$ (cmd args) construye también crea una subshell: 'echo $ (echo $ BASH_SUBSHELL)' –

1

De hecho, las llaves se ejecutan en una nueva subcadena, , pero solo si se grabó. El primer comando es con cat, la segunda sin:

[email protected]:~$ 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 
[email protected]:~$ 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 

En este caso 6768 es el PID del shell terminal, y 13159 es el PID de la subcapa se dirigió a las llaves.

Parece que {} se ejecutan en una subshell si (y solo si) se canaliza.

+2

La tubería crea la subcadena, no las llaves. –

+1

No, no es la tubería, son las llaves en conexión con la tubería. Verifique la salida de 'ps' contra' ps | cat' vs. '{ps; } | gato'.. – krlmlr

+2

¡Las llaves nunca invocan una subcamada! Solo las tuberías harán esto: http://unix.stackexchange.com/questions/127334/bash-subshell-creation-with-curly-braces – slm

Cuestiones relacionadas