El manual de bash dice:
La sustitución de comandos, los comandos agrupados entre paréntesis y los comandos asincrónicos se invocan en un entorno de subshell que es un duplicado del entorno de shell,
excepto que las trampas capturadas por el shell se restablecen a los valores que el shell heredó de su padre en invocación.
En este ejemplo, b
no es una variable de entorno, por lo que b
no existe en la subcapa creada por la sustitución de comandos. Entonces, ¿por qué c
asignó el valor de b
por sustitución de mando? ¿Es porque la expansión del parámetro ocurre para $b
? en el proceso de shell antes de crear un subshell para ejecutar echo 1
?
$ b=1
$ c=$(echo $b)
$ echo $c
1
Respuesta aceptada:
No, la subcapa se creó primero.
Un entorno de ejecución de shell contiene parámetros de shell establecidos por asignaciones de variables y variables de entorno. Se creó un entorno de subshell mediante la duplicación del entorno de shell, por lo que contiene todas las variables del entorno de shell actual.
Ver el ejemplo:
$ b=1
$ c=$(b=2; echo "$b")
$ echo "$c"
2
La salida es 2
en lugar de 1
.
Un entorno de subshell creado mediante la sustitución de comandos es diferente de un entorno de shell creado llamando al ejecutable de shell.
Cuando llamas al shell como:
$ bash -c :
el shell actual usó execve() para crear un nuevo proceso de shell, algo así como:
execve("/bin/bash", ["bash", "-c", ":"], [/* 64 vars */]) = 0
el último argumento pasado a execve
contiene todas las variables de entorno.
Es por eso que necesita exportar las variables para enviarlas a las variables de entorno, que se incluirán en los comandos ejecutados posteriormente:
$ a=; export a
$ strace -e execve bash -c :
execve("/bin/bash", ["bash", "-c", ":"], [/* 65 vars */]) = 0
+++ exited with 0 +++
Observe que las variables de entorno cambian de 64 a 65. Y las variables que no se exportan no se pasarán al nuevo entorno de shell:
$ a=; b=; export a
$ strace -e execve bash -c :
execve("/bin/bash", ["bash", "-c", ":"], [/* 65 vars */]) = 0
+++ exited with 0 +++
Observe que las variables de entorno siguen siendo 65.
En la sustitución de comandos, el shell usó fork() para crear un nuevo proceso de shell, que simplemente copió el entorno de shell actual, que contiene tanto el conjunto de variables como las variables de entorno.