De acuerdo con esto , colocar una lista de comandos entre llaves hace que la lista se ejecute en el contexto de shell actual. No se crea ninguna subshell .
Usando ps
para ver esto en acción
Esta es la jerarquía de proceso para una tubería de proceso ejecutada directamente en la línea de comando. 4398 es el PID para el shell de inicio de sesión:
sleep 2 | ps -H;
PID TTY TIME CMD
4398 pts/23 00:00:00 bash
29696 pts/23 00:00:00 sleep
29697 pts/23 00:00:00 ps
Ahora sigue la jerarquía de procesos para una tubería de proceso entre llaves entregadas directamente en la línea de comando. 4398 es el PID para el shell de inicio de sesión. Es similar a la jerarquía anterior que demuestra que todo se ejecuta en el contexto actual del shell :
{ sleep 2 | ps -H; }
PID TTY TIME CMD
4398 pts/23 00:00:00 bash
29588 pts/23 00:00:00 sleep
29589 pts/23 00:00:00 ps
Ahora, esta es la jerarquía del proceso cuando el sleep
en la tubería se coloca dentro de llaves (por lo tanto, dos niveles de llaves en total)
{ { sleep 2; } | ps -H; }
PID TTY TIME CMD
4398 pts/23 00:00:00 bash
29869 pts/23 00:00:00 bash
29871 pts/23 00:00:00 sleep
29870 pts/23 00:00:00 ps
¿Por qué bash
tiene que crear un subshell para ejecutarse sleep
en el tercer caso cuando la documentación establece que los comandos entre llaves se ejecutan en el contexto actual del shell?
{ sleep 2 | command ps -H; }
Respuestas:
En una tubería, todos los comandos se ejecutan simultáneamente (con sus stdout / stdin conectados por tuberías) en diferentes procesos.
En
Los tres comandos se ejecutan en diferentes procesos, por lo que al menos dos de ellos deben ejecutarse en un proceso secundario. Algunos shells ejecutan uno de ellos en el proceso de shell actual (si está integrado
read
o si la canalización es el último comando del script), pero losbash
ejecuta en su propio proceso por separado (excepto con lalastpipe
opción enbash
versiones recientes y bajo algunas condiciones específicas ){...}
agrupa comandos. Si ese grupo es parte de una tubería, tiene que ejecutarse en un proceso separado al igual que un comando simple.En:
Necesitamos un shell para evaluar que
a; b "$?"
es un proceso separado, por lo que necesitamos un subshell. El shell podría optimizar al no bifurcar,b
ya que es el último comando que se ejecuta en ese grupo. Algunas conchas lo hacen, pero aparentemente nobash
.fuente
bash -c "sleep 112345 | cat | cat "
, solo veo una bash creada y luego 3 hijos sin ninguna otra subestimación intercalada.a; b "$?"
? ¿Existe realmente una necesidad fundamental de un subsheel, o tal vez es una decisión de diseño / implementación en bash?eval
), pero la evaluación (ejecute el primer comando, espere, ejecute el segundo) es hecho en el niño, el que tiene stdout conectado a la tubería.{ sleep 2 | ps -H; }
el padre bash vesleep 2
que requiere un fork / exec. Pero en{ { sleep 2; } | ps -H; }
el padre bash ve{ sleep 2; }
en otras palabras, algún código bash. Parece que el padre puede manejar el fork / execsleep 2
pero genera un nuevo bash recursivamente para manejar el código bash encontrado. Ese es mi entendimiento, ¿tiene sentido?Anidar las llaves parece indicar que está creando un nivel adicional de alcance que requiere que se invoque un nuevo subconcha. Puede ver este efecto con la segunda copia de Bash en su
ps -H
salida.Solo los procesos estipulados en el primer nivel de llaves se ejecutan dentro del alcance del shell Bash original. Cualquier llave rizada anidada se ejecutará en su propio shell Bash con ámbito.
Ejemplo
Sacando la
| ps -H
mezcla solo para que podamos ver las llaves rizadas anidadas, podemos ejecutarps auxf | less
en otro shell.¡Pero espera hay mas!
Sin embargo, si saca las tuberías y usa esta forma de comando, veremos lo que realmente esperaría:
Ahora, en la ventana de observación resultante, recibimos una actualización cada 2 segundos de lo que está sucediendo:
Aquí está el primero
sleep 10
:Aquí está el segundo
sleep 10
:Aquí está el tercero
sleep 10
:Observe que los tres durmientes, aunque se invocan en diferentes niveles de anidación de llaves, se mantienen dentro del PID 5676 de Bash. Así que creo que su problema es autoinfligido con el uso de
| ps -H
.Conclusiones
El uso de
| ps -H
(es decir, la tubería) está causando un subconcha adicional, así que no use ese método cuando intente interrogar qué está sucediendo.fuente
Publicaré los resultados de mis pruebas, lo que me lleva a la conclusión de que bash crea un subconjunto para un comando de grupo si y solo si es parte de la canalización, es similar a como se llamaría alguna función que también se llamaría en sub-shell.
fuente