Bash e subshells

5

Pelo que eu recebi dos documentos on-line, o seguinte deve gerar um subshell para a parte do comando incorporado com {} :

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

No entanto, como você pode ver, nos dois casos, o ID do processo é o mesmo. o que estou perdendo? Obrigado por todos os ponteiros.

    
por Amit 05.10.2013 / 11:52

2 respostas

7

O {} apenas agrupa os comandos no shell atual, enquanto () inicia um novo subshell. No entanto, o que você está fazendo é colocar os comandos agrupados em segundo plano, o que é de fato um novo processo; se estivesse no processo atual, não poderia ser feito em segundo plano. É mais fácil, IMHO, ver esse tipo de coisa com 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

Observe que o comando bash é iniciado e, em seguida, cria um novo filho com clone() . Usar a opção -f para strace significa que ela também segue processos filhos, mostrando ainda outra bifurcação (bem, "clone") quando ela é executada. Se você deixar o -f off, verá apenas uma chamada clone quando criar o processo em 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)                           = ?

Se você realmente quer apenas saber com que frequência está criando novos processos, pode simplificá-lo ainda mais observando apenas as chamadas bifurcadas e clonadas:

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
    
por 06.10.2013 / 20:28
5

Atualização:

Por favor, veja a resposta acima. Com {}, não estou realmente criando um subshell. Em vez disso, o back ground aqui me dá a resposta que eu estava procurando.

Ok, basicamente eu estava usando o "indicador" incorreto de subshells sendo criados. Aprendi sobre o BASHPID de aqui e usando isso além de BASH_SUBSHELL , Eu posso ver que uma subshell está realmente sendo criada.

comando de teste:

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

Outro comando de teste também mostra o ID do processo pai para o shell e o subshell:

$ bash -c '{ sleep 10; echo "Sleeping process", $BASHPID, $BASH_SUBSHELL, $PPID; }  & echo $BASHPID, $PPID; '
12411, 9128
$ Sleeping process, 12412, 1, 9128
    
por 05.10.2013 / 12:03