Por lo que he leído, poner un comando entre paréntesis debería ejecutarlo en un subshell, similar a ejecutar un script. Si esto es cierto, ¿cómo ve la variable x si x no se exporta?
x=1
Ejecutar (echo $x)
en la línea de comando da como resultado 1
La ejecución echo $x
de un script no produce nada, como se esperaba
Respuesta1
Un subshell comienza como una copia casi idéntica del proceso del shell original. Debajo del capó, el caparazón llama alfork
llamada al sistema 1 , que crea un nuevo proceso cuyo código y memoria son copias 2 . Cuando se crea la subcapa, existen muy pocas diferencias entre ésta y su capa principal. En particular, tienen las mismas variables. Incluso la $$
variable especial mantiene el mismo valor en los subshells: es el ID del proceso del shell original. De manera similar $PPID
es el PID del padre del shell original.
Algunos shells cambian algunas variables en el subshell. Bash ≥4.0 se establece BASHPID
en el PID del proceso de shell, que cambia en subcapas. Bash, zsh y mksh se organizan para $RANDOM
producir valores diferentes en el nivel principal y en el subnivel. Pero aparte de casos especiales integrados como estos, todas las variables tienen el mismo valor en el subshell que en el shell original, el mismo estado de exportación, el mismo estado de solo lectura, etc. Todas las definiciones de funciones, definiciones de alias, opciones de shell y otras configuraciones también se heredan.
Un subshell creado por (…)
tiene los mismos descriptores de archivo que su creador. Algunos otros medios para crear subcapas modifican algunos descriptores de archivos antes de ejecutar el código de usuario; Por ejemplo, el lado izquierdo de un tubo discurre por una subcapa 3 con salida estándar conectada al tubo. El subshell también comienza con el mismo directorio actual, la misma máscara de señal, etc. Una de las pocas excepciones es que los subshells no heredan trampas personalizadas: las señales ignoradas ( ) permanecen ignoradas en el subshell, pero otras trampas (trap '' SIGNAL
trap CODE
SEÑAL) se restablecen a la acción predeterminada 4 .
Por tanto, una subcapa es diferente de ejecutar un script. Un script es un programa independiente. Casualmente, este programa separado podría ser también un script ejecutado por el mismo intérprete que el padre, pero esta coincidencia no le da al programa separado ninguna visibilidad especial sobre los datos internos del padre. Las variables no exportadas son datos internos, por lo que cuando el intérprete del script de shell secundario esejecutado, no ve estas variables. Las variables exportadas, es decir, las variables de entorno, se transmiten a los programas ejecutados.
De este modo:
x=1
(echo $x)
se imprime 1
porque el subshell es una replicación del shell que lo generó.
x=1
sh -c 'echo $x'
sucede que ejecuta un shell como un proceso hijo de un shell, pero el x
de la segunda línea no tiene más conexión con el x
de la segunda línea que en
x=1
perl -le 'print $x'
o
x=1
python -c 'print x'
1 A menos que el shell optimice la bifurcación, pero la emule tanto como sea necesario para preservar el comportamiento del código que está ejecutando. Ksh93 optimiza mucho, otros shells en su mayoría no lo hacen.
2 Semánticamente, son copias. Desde una perspectiva de implementación, se está compartiendo mucho.
3 Para el lado derecho, depende de la carcasa.
4 Si prueba esto, tenga en cuenta quecosas como$(trap)
Puede informar sobre las trampas del caparazón original. Tenga en cuenta también que muchos shells tienen errores en los casos de esquina que involucran trampas. Por ejemploninjaljobserva que a partir de bash 4.3, bash -x -c 'trap "echo ERR at \$BASH_SUBSHELL \$BASHPID" ERR; set -E; false; echo one subshell; (false); echo two subshells; ( (false) )'
ejecuta la ERR
trampa desde el subcapa anidado en el caso de "dos subcapas", pero no la ERR
trampa desde el subcapa intermedio; set -E
la opción debería propagar la ERR
trampa a todos los subcapas, pero el subcapa intermedio está optimizado y también lo está. No está allí para ejecutar su ERR
trampa.
Respuesta2
Obviamente, sí, como dice toda la documentación, un comando entre paréntesis se ejecuta en un subshell.
La subcapa hereda una copia de todas las variables del padre. La diferencia es que cualquier cambio que realice en el subnivel no se realiza también en el nivel principal.
La página de manual de ksh deja esto un poco más claro que la de bash:
man ksh
:
Un comando entre paréntesis se ejecuta en un subshell sin eliminar las variables no exportadas.
man bash
:
(
lista)
list se ejecuta en un entorno de subshell (consulte ENTORNO DE EJECUCIÓN DE COMANDOS a continuación). Las asignaciones de variables y los comandos integrados que afectan el entorno del shell no permanecen vigentes una vez que se completa el comando.
ENTORNO DE EJECUCIÓN DE COMANDOS
El shell tiene un entorno de ejecución, que consta de lo siguiente: [...] parámetros del shell que se establecen mediante asignación de variables [...].
La sustitución de comandos, los comandos agrupados entre paréntesis y los comandos asíncronos se invocan en un entorno de subshell que es un duplicado del entorno de shell, [...]