Il Learning Bash Book afferma che una subshell erediterà solo variabili di ambiente e descrittori di file, ecc., e che non erediterà variabili che non vengono esportate:
$ var=15
$ (echo $var)
15
$ ./file # this file include the same command echo $var
$
Come so, la shell creerà due subshell per ()
e per ./file
, ma perché nel ()
case la subshell identifica il var
variabile anche se non è esportata e nel ./file
caso non l'ha identificato?
# Strace for ()
clone(child_stack=0, flags=CLONE_CHILD_CLEARTID|CLONE_CHILD_SETTID|SIGCHLD, child_tidptr=0x7f24558b1a10) = 25617
# Strace for ./file
clone(child_stack=0, flags=CLONE_CHILD_CLEARTID|CLONE_CHILD_SETTID|SIGCHLD, child_tidptr=0x7f24558b1a10) = 25631
Ho provato a usare strace
per capire come ciò avvenga e sorprendentemente ho scoperto che bash utilizzerà gli stessi argomenti per la chiamata di sistema clone, quindi questo significa che sia il processo biforcato in ()
e ./file
dovrebbe avere lo stesso spazio degli indirizzi di processo del genitore, quindi perché in ()
case è la variabile visibile alla subshell e lo stesso non accade per il ./file
caso, anche se gli stessi argomenti si basano sulla chiamata di sistema clone?
Risposta accettata:
Il libro Learning Bash è sbagliato. Le subshell ereditano tutte le variabili. Anche $$
(il PID della shell originale) viene mantenuto. Il motivo è che per una subshell, la shell si limita a eseguire il fork e non esegue una nuova shell (al contrario, quando si digita ./file
, viene eseguito un nuovo comando, ad es. un nuovo guscio; nell'output di strace, guarda execve
e simili). Quindi, in pratica, è solo una copia (con alcune differenze documentate).
Nota:questo non è specifico per bash; questo vale per qualsiasi shell.