Il manuale di Bash dice:
La sostituzione dei comandi, i comandi raggruppati tra parentesi e i comandi asincroni vengono invocati in un ambiente di sottoshell che è un duplicato dell'ambiente di shell,
tranne per il fatto che le trap catturate dalla shell vengono reimpostate sui valori che la shell ha ereditato dal suo genitore in invocazione.
In questo esempio,b
non è una variabile di ambiente, quindi b
non esiste nella subshell creata dalla sostituzione del comando. Allora perché c
assegnato il valore di b
per sostituzione di comando? È perché l'espansione del parametro avviene per $b
nel processo della shell prima di creare una subshell per eseguire echo 1
?
$ b=1
$ c=$(echo $b)
$ echo $c
1
Risposta accettata:
No, è stata creata prima la subshell.
Un ambiente di esecuzione della shell contiene parametri della shell impostati da assegnazioni di variabili e variabili di ambiente. Un ambiente subshell è stato creato duplicando l'ambiente shell, quindi contiene tutte le variabili dell'ambiente shell corrente.
Vedi l'esempio:
$ b=1
$ c=$(b=2; echo "$b")
$ echo "$c"
2
L'output è 2
invece di 1
.
Un ambiente di sottoshell creato dalla sostituzione di comandi è diverso con un ambiente di shell creato chiamando l'eseguibile della shell.
Quando chiami la shell come:
$ bash -c :
la shell corrente ha usato execve() per creare un nuovo processo di shell, qualcosa come:
execve("/bin/bash", ["bash", "-c", ":"], [/* 64 vars */]) = 0
l'ultimo argomento passato a execve
contiene tutte le variabili d'ambiente.
Ecco perché è necessario esportare le variabili per inviarle alle variabili di ambiente, che verranno incluse nei comandi eseguiti successivamente:
$ a=; export a
$ strace -e execve bash -c :
execve("/bin/bash", ["bash", "-c", ":"], [/* 65 vars */]) = 0
+++ exited with 0 +++
Nota che le variabili di ambiente cambiano da 64 a 65. E le variabili che non vengono esportate non verranno passate al nuovo ambiente shell:
$ a=; b=; export a
$ strace -e execve bash -c :
execve("/bin/bash", ["bash", "-c", ":"], [/* 65 vars */]) = 0
+++ exited with 0 +++
Si noti che le variabili di ambiente sono ancora 65.
In sostituzione del comando, la shell ha utilizzato fork() per creare un nuovo processo di shell, che ha appena copiato l'ambiente della shell corrente, che contiene sia il set di variabili che le variabili di ambiente.