Bash y subcapas

Bash y subcapas

Por lo que deduzco de los documentos en línea, lo siguiente debería generar un subshell para la parte del comando incrustado con {}:

$ bash -c '{ sleep 10; echo "Sleeping process", $$; }  & echo $$; '
11237
 Sleeping process, 11237

Sin embargo, como puede ver, en ambos casos el ID del proceso es el mismo. ¿Qué me estoy perdiendo? Gracias por cualquier consejo.

Respuesta1

Just {}agrupa los comandos en el shell actual, mientras ()inicia un nuevo subshell. Sin embargo, lo que estás haciendo es poner los comandos agrupados en segundo plano, lo que de hecho es un proceso nuevo; si estuviera en el proceso actual, no sería posible que estuviera en segundo plano. Es más fácil, en mi humilde opinión, ver este tipo de cosas con strace:

sauer@humpy:~$ strace -f -etrace=process bash -c '{ sleep 10; echo "Sleeping process", $BASHPID, $BASH_SUBSHELL; }  & echo $BASHPID;' > /tmp/file
execve("/bin/bash", ["bash", "-c", "{ sleep 10; echo \"Sleeping proce"...], [/* 20 vars */]) = 0
arch_prctl(ARCH_SET_FS, 0x7f15a90da700) = 0
clone(Process 25347 attached
child_stack=0, flags=CLONE_CHILD_CLEARTID|CLONE_CHILD_SETTID|SIGCHLD, child_tidptr=0x7f15a90da9d0) = 25347
[pid 25346] exit_group(0)               = ?
clone(Process 25348 attached (waiting for parent)
Process 25348 resumed (parent 25347 ready)
child_stack=0, flags=CLONE_CHILD_CLEARTID|CLONE_CHILD_SETTID|SIGCHLD, child_tidptr=0x7f15a90da9d0) = 25348
[pid 25348] execve("/bin/sleep", ["sleep", "10"], [/* 20 vars */] <unfinished ...>
[pid 25347] wait4(-1, Process 25347 suspended
 <unfinished ...>
[pid 25348] <... execve resumed> )      = 0
[pid 25348] arch_prctl(ARCH_SET_FS, 0x7f922ad16700) = 0
[pid 25348] exit_group(0)               = ?
Process 25347 resumed
Process 25348 detached
<... wait4 resumed> [{WIFEXITED(s) && WEXITSTATUS(s) == 0}], 0, NULL) = 25348
--- SIGCHLD (Child exited) @ 0 (0) ---
wait4(-1, 0x7fffaa432ad8, WNOHANG, NULL) = -1 ECHILD (No child processes)
exit_group(0)                           = ?
Process 25347 detached

sauer@humpy:~$ cat /tmp/file
25346
Sleeping process, 25347, 1

Tenga en cuenta que el comando bash se inicia y luego crea un nuevo elemento secundario con clone(). Usar la opción -f para rastrear significa que también sigue los procesos secundarios, mostrando otra bifurcación (bueno, "clon") cuando ejecuta la suspensión. Si deja el -f desactivado, verá solo una llamada de clonación cuando crea el proceso en segundo plano:

sauer@humpy:~$ strace -etrace=clone bash -c '{ sleep 10; echo "Sleeping process", $BASHPID, $BASH_SUBSHELL; }  & echo $BASHPID;' > /tmp/file
clone(child_stack=0, flags=CLONE_CHILD_CLEARTID|CLONE_CHILD_SETTID|SIGCHLD, child_tidptr=0x7f2bdd5399d0) = 26394
sauer@humpy:~$ strace -etrace=process bash -c '{ sleep 10; echo "Sleeping process", $BASHPID, $BASH_SUBSHELL; }  & echo $BASHPID;' > /dev/null
execve("/bin/bash", ["bash", "-c", "{ sleep 10; echo \"Sleeping proce"...], [/* 20 vars */]) = 0
arch_prctl(ARCH_SET_FS, 0x7fd01ae86700) = 0
clone(child_stack=0, flags=CLONE_CHILD_CLEARTID|CLONE_CHILD_SETTID|SIGCHLD, child_tidptr=0x7fd01ae869d0) = 26706
exit_group(0)                           = ?

Si realmente solo desea saber con qué frecuencia crea nuevos procesos, puede simplificarlo aún más observando únicamente las llamadas de bifurcación y clonación:

sauer@humpy:~$ strace -etrace=fork,clone bash -c '{ sleep 10; echo "Sleeping process", $BASHPID, $BASH_SUBSHELL; }  & echo $BASHPID;' > /dev/null
clone(child_stack=0, flags=CLONE_CHILD_CLEARTID|CLONE_CHILD_SETTID|SIGCHLD, child_tidptr=0x7f467fa769d0) = 27025

Respuesta2

Actualizar:

Por favor vea la respuesta anterior. Con {}, en realidad no estoy creando una subcapa. En cambio, la base aquí me da la respuesta que estaba buscando.

Bien, básicamente estaba usando el "indicador" incorrecto de subcapas que se estaban creando. Aprendí sobre el BASHPIDdeaquíy al usarlo además de BASH_SUBSHELL, puedo ver que efectivamente se está creando una subcapa.

Comando de prueba:

$ bash -c '{ sleep 10; echo "Sleeping process", $BASHPID, $BASH_SUBSHELL; }  & echo $BASHPID; '
12074
 Sleeping process, 12075, 1

Otro comando de prueba para mostrar también el ID del proceso principal tanto para el shell como para el subshell:

$ bash -c '{ sleep 10; echo "Sleeping process", $BASHPID, $BASH_SUBSHELL, $PPID; }  & echo $BASHPID, $PPID; '
12411, 9128
$ Sleeping process, 12412, 1, 9128

información relacionada