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.
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. –
Necesitas un espacio después del '{', al menos en mi versión de 'bash'. – krlmlr
$ (cmd args) construye también crea una subshell: 'echo $ (echo $ BASH_SUBSHELL)' –