Learning Bash Book menciona que una subshell heredará solo variables de entorno y descriptores de archivos, etc., y que no heredará variables que no se exportan:
$ var=15
$ (echo $var)
15
$ ./file # this file include the same command echo $var
$
Como sé, el shell creará dos subshell para ()y para ./file, pero ¿por qué en el ()caso el subshell identifica la varvariable aunque no se exporta y en el ./filecaso no la identifica?
# Strace for ()
clone(child_stack=0, flags=CLONE_CHILD_CLEARTID|CLONE_CHILD_SETTID|SIGCHLD, child_tidptr=0x7f24558b1a10) = 25617
# Strace for ./file
clone(child_stack=0, flags=CLONE_CHILD_CLEARTID|CLONE_CHILD_SETTID|SIGCHLD, child_tidptr=0x7f24558b1a10) = 25631
Traté de usar stracepara descubrir cómo sucede esto y, sorprendentemente, descubrí que bash usará los mismos argumentos para la llamada al sistema de clonación, por lo que esto significa que tanto el proceso bifurcado ()como ./fileel mismo deben tener el mismo espacio de dirección del proceso del padre, entonces ¿por qué? en el ()caso, ¿la variable es visible para la subshell y no ocurre lo mismo para el ./filecaso, aunque los mismos argumentos se basan en la llamada al sistema de clonación?

Respuestas:
El libro Learning Bash está mal. Las subcapas heredan todas las variables. Incluso
$$(el PID del shell original) se mantiene. La razón es que para un subshell, el shell simplemente se bifurca y no ejecuta un nuevo shell (por el contrario, cuando escribe./file, se ejecuta un nuevo comando, por ejemplo, un nuevo shell; en la salida de strace, mireexecvey similar) . Entonces, básicamente, es solo una copia (con algunas diferencias documentadas).Nota: esto no es específico de bash; Esto es cierto para cualquier shell.
fuente
-fopción destracerastrear niños también? Eso es necesario para encontrar los ejecutivos.Tanto usted como el libro están confundiendo un subshell con un subproceso que es un shell.
Algunas construcciones de shell dan como resultado que el shell bifurque un proceso hijo. En Linux,
forkes un caso especial de laclonellamada al sistema más general , que observó en elstraceregistro. El niño ejecuta una parte del script de shell. El proceso hijo se llama subshell . La construcción más directa escommand1 &: secommand1ejecuta en un subshell y los comandos posteriores se ejecutan en el shell principal. Otras construcciones que crean un subshell incluyen la sustitución de comandos$(command2)y tuberíascommand3 | command4(secommand3ejecuta en un subshell, secommand4ejecuta en un subshell en la mayoría de los shells pero no en ksh o zsh).Una subshell es una copia del proceso padre, por lo que no solo tiene las mismas variables de entorno, sino también las mismas definiciones internas: variables (incluido
$$el ID de proceso del proceso de shell original), funciones, alias, opciones, etc. Antes de ejecutar el código en el subshell, bash establece la variableBASHPIDen el ID del proceso secundario.Cuando ejecuta
./file, esto ejecuta un comando externo. Primero, el shell bifurca un proceso hijo; entonces este proceso hijo ejecuta (con laexecvellamada al sistema) el archivo ejecutable./file. Un proceso hijo hereda los atributos de proceso de sus padres: entorno, directorio actual, etc. Los aspectos internos de la aplicación se pierden en laexecvellamada: las variables, funciones, etc. no exportadas son nociones bash que el núcleo no conoce, y se pierden cuando bash ejecuta otro programa. Incluso si ese otro programa resulta ser un script bash, es ejecutado por una nueva instancia de bash que no sabe o no le importa que su proceso padre también sea una instancia de bash. Por lo tanto, una variable de shell (variable no exportada) no sobreviveexecve.fuente