Entiendo que la sintaxis de subshell es (<commands...>)
, ¿es $()
solo una subshell de la que puede recuperar valores variables?
Nota: Esto se aplica a bash 4.4 basado en una redacción diferente en su documentación.
Entiendo que la sintaxis de subshell es (<commands...>)
, ¿es $()
solo una subshell de la que puede recuperar valores variables?
Nota: Esto se aplica a bash 4.4 basado en una redacción diferente en su documentación.
Respuestas:
$(…)
es un subshell por definición: es una copia del estado de ejecución del shell¹, y los cambios en el estado realizado en el subshell no tienen impacto en el padre. Una subshell generalmente se implementa bifurcando un nuevo proceso (pero algunas shells pueden optimizar esto en algunos casos).
No es un subshell del que puede recuperar valores variables. Si los cambios en las variables tuvieran un impacto en el padre, no sería una subshell. Es un subshell cuya salida puede recuperar el padre. El subshell creado por $(…)
tiene su salida estándar establecida en una tubería, y el padre lee de esa tubería y recoge la salida.
Hay varias otras construcciones que crean una subshell. Creo que esta es la lista completa de bash:
( … )
no hace más que crear un subshell y esperar a que termine). Contraste con { … }
qué grupos ordena únicamente para fines sintácticos y no crea una subshell.… &
crea una subshell y no espera a que termine.… | …
crea dos subcapas, una para el lado izquierdo y otra para el lado derecho, y espera a que ambas terminen. El shell crea una tubería y conecta la salida estándar del lado izquierdo al extremo de escritura de la tubería y la entrada estándar del lado derecho al extremo de lectura. En algunos shells (ksh88, ksh93, zsh, bash con la lastpipe
opción establecida y efectiva), el lado derecho se ejecuta en el shell original, por lo que la construcción de la tubería solo crea un subshell.$(…)
(también deletreado `…`
) crea una subshell con su salida estándar establecida en una tubería, recopila la salida en el padre y se expande a esa salida, menos sus nuevas líneas finales. (Y el resultado puede estar más sujeto a la división y el bloqueo, pero esa es otra historia).<(…)
crea una subshell con su salida estándar establecida en una tubería y se expande al nombre de la tubería. El padre (o algún otro proceso) puede abrir la tubería para comunicarse con la subshell. >(…)
hace lo mismo pero con la tubería en la entrada estándar.coproc …
crea una subshell y no espera a que termine. La entrada y salida estándar del subshell se configuran en una tubería con el padre conectado al otro extremo de cada tubería.${...}
en la respuesta?
command | { read line; … }
(dependiendo del shell, line
puede o no estar disponible después de la tubería). Todas las formas implican un subshell porque el comando que produce la salida tiene que ejecutarse independientemente del shell que lee la entrada. Si el comando es puramente interno al shell (solo construcciones y construcciones de shell, no comandos externos), el shell podría no crear un subproceso, pero eso es solo una optimización, todavía crea un subshell.
Desde la página del comando man bash (1) en bash versión 4.4, sección "EXPANSIÓN", subsección "Sustitución de comandos":
Bash realiza la expansión ejecutando
command
en un entorno de subshell [...]
bash
manual no menciona ninguna subshell: Bash performs the expansion by executing command and replacing the command substitution with the standard output of the command, with any trailing newlines deleted.
me pregunto si fue una omisión deliberada.