As diferenças entre os shells são devidas a diferenças na configuração do processo. dash
configura os redirecionamentos antes de bifurcar, então /proc/self
aponta para o shell; bash
e zsh
os configuram após o bifurcação, portanto, /proc/self
aponta para o novo processo. Você pode ver isso acontecer com strace -f
:
-
strace -f dash -c '/bin/cat /proc/self/comm - </proc/self/comm'
mostra (entre muitas outras coisas)open("/proc/self/comm", O_RDONLY) = 3 fcntl(0, F_DUPFD, 10) = 10 close(0) = 0 fcntl(10, F_SETFD, FD_CLOEXEC) = 0 dup2(3, 0) = 0 close(3) = 0 clone(child_stack=NULL, flags=CLONE_CHILD_CLEARTID|CLONE_CHILD_SETTID|SIGCHLD, child_tidptr=0x7f12581299d0) = 7743 strace: Process 7743 attached [pid 7742] wait4(-1, <unfinished ...> [pid 7743] execve("/bin/cat", ["/bin/cat", "/proc/self/comm", "-"], [/* 43 vars */]) = 0
(
/proc/self/comm
é aberto antes da chamada do sistemaclone
, que é onde o processo se bifurca); -
strace -f bash -c '/ bin / cat / proc / self / comm -
clone(child_stack=NULL, flags=CLONE_CHILD_CLEARTID|CLONE_CHILD_SETTID|SIGCHLD, child_tidptr=0x7fb506bdee10) = 8106 strace: Process 8106 attached [... snip a ton of signal-handling setup ...] [pid 8106] open("/proc/self/comm", O_RDONLY) = 3 [pid 8106] dup2(3, 0) = 0 [pid 8106] close(3) = 0 [pid 8106] execve("/bin/cat", ["/bin/cat", "/proc/self/comm", "-"], [/* 43 vars */]) = 0
(
/proc/self/comm
é aberto após a chamadaclone
, no processo filho, 8106).
Entender por que environ
aparece vazio requer um pouco mais de explicação. Quando /proc/<pid>/environ
é aberto , o kernel salva uma cópia do ponteiro para a tarefa mm_struct
, que contém ponteiros para o ambiente. Mas execve
, que é usado para iniciar o processo cat
, cria um novo mm_struct
para o processo . Assim, o redirecionamento acaba apontando para informações obsoletas e quando cat
lê suas entradas, ele não vê seu ambiente real. O ambiente que ele faz deve ser uma cópia de seus pais, mas as camadas envolvidas limpam antes de bifurcar e configurar o novo ambiente (que é configurado por execve
).