Compare a execução de um comando diretamente e em segundo plano

0

No Ubuntu, executo date em um shell bash interativo cujo pid é 6913 e, ao mesmo tempo, rastreio o shell bash de outro shell bash interativo por strace .

Usando o rastreamento, eu gostaria de entender como date é executado diretamente (veja aqui para rastreamento saída) e em segundo plano (consulte aqui para rastrear a saída):

Ao executar date , a saída do rastreamento do primeiro shell 6913 no segundo shell é:

$ sudo strace -f -e trace=process -p 6913
[sudo] password for t: 
Process 6913 attached
clone(Process 12918 attached
child_stack=0, flags=CLONE_CHILD_CLEARTID|CLONE_CHILD_SETTID|SIGCHLD, child_tidptr=0x7f457c05ca10) = 12918
[pid  6913] wait4(-1,  <unfinished ...>
[pid 12918] execve("/bin/date", ["date"], [/* 66 vars */]) = 0
[pid 12918] arch_prctl(ARCH_SET_FS, 0x7ff00c632740) = 0
[pid 12918] exit_group(0)               = ?
[pid 12918] +++ exited with 0 +++
<... wait4 resumed> [{WIFEXITED(s) && WEXITSTATUS(s) == 0}], WSTOPPED|WCONTINUED, NULL) = 12918
--- SIGCHLD {si_signo=SIGCHLD, si_code=CLD_EXITED, si_pid=12918, si_status=0, si_utime=0, si_stime=0} ---
wait4(-1, 0x7ffea6781518, WNOHANG|WSTOPPED|WCONTINUED, NULL) = -1 ECHILD (No child processes)

Ao executar date & , a saída do rastreamento do primeiro shell 6913 no segundo shell é:

$ sudo strace -f -e trace=process -p 6913
Process 6913 attached
clone(Process 12931 attached
child_stack=0, flags=CLONE_CHILD_CLEARTID|CLONE_CHILD_SETTID|SIGCHLD, child_tidptr=0x7f457c05ca10) = 12931
[pid 12931] execve("/bin/date", ["date"], [/* 66 vars */]) = 0
[pid 12931] arch_prctl(ARCH_SET_FS, 0x7f530c5ee740) = 0
[pid 12931] exit_group(0)               = ?
[pid 12931] +++ exited with 0 +++
--- SIGCHLD {si_signo=SIGCHLD, si_code=CLD_EXITED, si_pid=12931, si_status=0, si_utime=0, si_stime=0} ---
wait4(-1, [{WIFEXITED(s) && WEXITSTATUS(s) == 0}], WNOHANG|WSTOPPED|WCONTINUED, NULL) = 12931
wait4(-1, 0x7ffea6780718, WNOHANG|WSTOPPED|WCONTINUED, NULL) = -1 ECHILD (No child processes)

Ao executar echo $b & , a saída do rastreamento do primeiro shell 6913 no segundo shell é:

$ sudo strace -f -e trace=process -p 6913
Process 6913 attached
clone(Process 31319 attached
child_stack=0, flags=CLONE_CHILD_CLEARTID|CLONE_CHILD_SETTID|SIGCHLD, child_tidptr=0x7f457c05ca10) = 31319
[pid 31319] exit_group(0)               = ?
[pid 31319] +++ exited with 0 +++
--- SIGCHLD {si_signo=SIGCHLD, si_code=CLD_EXITED, si_pid=31319, si_status=0, si_utime=0, si_stime=0} ---
wait4(-1, [{WIFEXITED(s) && WEXITSTATUS(s) == 0}], WNOHANG|WSTOPPED|WCONTINUED, NULL) = 31319
wait4(-1, 0x7ffea6780718, WNOHANG|WSTOPPED|WCONTINUED, NULL) = -1 ECHILD (No child processes)

Ao executar { date; } & , a saída do rastreamento do primeiro shell 6913 no segundo shell é:

$ sudo strace -f -e trace=process -p 6913
Process 6913 attached
clone(child_stack=0, flags=CLONE_CHILD_CLEARTID|CLONE_CHILD_SETTID|SIGCHLD, child_tidptr=0x7f457c05ca10) = 31294
Process 31294 attached
[pid 31294] clone(Process 31295 attached
child_stack=0, flags=CLONE_CHILD_CLEARTID|CLONE_CHILD_SETTID|SIGCHLD, child_tidptr=0x7f457c05ca10) = 31295
[pid 31294] wait4(-1,  <unfinished ...>
[pid 31295] execve("/bin/date", ["date"], [/* 67 vars */]) = 0
[pid 31295] arch_prctl(ARCH_SET_FS, 0x7f78b7f0b740) = 0
[pid 31295] exit_group(0)               = ?
[pid 31295] +++ exited with 0 +++
[pid 31294] <... wait4 resumed> [{WIFEXITED(s) && WEXITSTATUS(s) == 0}], 0, NULL) = 31295
[pid 31294] --- SIGCHLD {si_signo=SIGCHLD, si_code=CLD_EXITED, si_pid=31295, si_status=0, si_utime=0, si_stime=0} ---
[pid 31294] wait4(-1, 0x7ffea67811d8, WNOHANG, NULL) = -1 ECHILD (No child processes)
[pid 31294] exit_group(0)               = ?
[pid 31294] +++ exited with 0 +++
--- SIGCHLD {si_signo=SIGCHLD, si_code=CLD_EXITED, si_pid=31294, si_status=0, si_utime=0, si_stime=0} ---
wait4(-1, [{WIFEXITED(s) && WEXITSTATUS(s) == 0}], WNOHANG|WSTOPPED|WCONTINUED, NULL) = 31294
wait4(-1, 0x7ffea6780718, WNOHANG|WSTOPPED|WCONTINUED, NULL) = -1 ECHILD (No child processes)

Perguntas:

  1. No que diz respeito a executar o comando date , executá-lo diretamente e executá-lo em segundo plano parece fazer o mesmo coisa:

    Ao executar o comando diretamente, o shell bash original 6913 clone() em si e, em seguida, seu clone 12918 execve() o comando.

    Ao executar o comando em segundo plano, o shell bash original 6913 clone() em si e, em seguida, seu clone 12931 execve() o comando.

    Ambas as chamadas clone() apenas uma vez. Quais são as diferenças entre eles?

  2. Não importa se o comando é externo ou interno, por exemplo, executando date& e executando echo $b & , ambos chamam clone() uma vez. Por que essa diferença?

  3. Compare a execução de date & e { date; } & . O manual do bash diz chaves não criam subcamadas. Por que suas saídas de rastreamento diferente:

    • na saída de rastreamento de date& , há apenas um clone (6913 clone() para criar 12931) e o clone 12931 execve() date ,
    • na saída de rastreamento de { date; }& , há dois clones (6913 clone() para criar 31294 e 31294 clone() para criar 31295) e o último clone 31295 execve() date
  4. Diz-se que um comando em execução em segundo plano (por exemplo, date& ) pode acessar um local variável no shell pai, porque ele é executado em um subshell do shell pai, enquanto um comando executado diretamente não pode (por exemplo, date ), porque ele não é executado em uma sub-shell do shell pai. Nós podemos explicar a diferença usando as saídas de rastreamento?

    $ b=1
    $ { echo $b; } &
    [1] 31214
    1
    

    Aqui b é variável local para o shell pai e não uma variável de ambiente. O subshell criado por & copia b do shell pai, portanto, b é ecoado com 1 do valor do shell pai. Eu criei este exemplo, a partir de outro que usa substituição de comando em vez de plano de fundo, que criam um subshell para executar um comando.

por Tim 03.03.2016 / 09:34

0 respostas