Capisco che la sintassi della subshell sia (<commands...>)
, è $()
solo una subshell da cui è possibile recuperare i valori delle variabili?
Nota: questo vale per bash 4.4 in base a una diversa formulazione nella loro documentazione.
Capisco che la sintassi della subshell sia (<commands...>)
, è $()
solo una subshell da cui è possibile recuperare i valori delle variabili?
Nota: questo vale per bash 4.4 in base a una diversa formulazione nella loro documentazione.
Risposte:
$(…)
è una subshell per definizione: è una copia dello stato di runtime della shell¹, e le modifiche allo stato effettuate nella subshell non hanno alcun impatto sul genitore. Una subshell viene in genere implementata tramite il fork di un nuovo processo (ma alcune shell possono ottimizzarlo in alcuni casi).
Non è una subshell da cui è possibile recuperare i valori delle variabili. Se le modifiche alle variabili avessero un impatto sul genitore, non sarebbe una subshell. È una subshell il cui output può essere recuperato dal genitore. La subshell creata da $(…)
ha l'output standard impostato su una pipe e il padre legge da quella pipe e raccoglie l'output.
Esistono molti altri costrutti che creano una subshell. Penso che questa sia la lista completa di bash:
( … )
non fa altro che creare una subshell e attendere che termini). Contrasto con { … }
quale gruppo comanda esclusivamente a fini sintattici e non crea una sottostruttura.… &
crea una subshell e non aspetta che termini.… | …
crea due subshells, uno per il lato sinistro e uno per il lato destro, e attende che entrambi terminino. La shell crea una pipe e collega l'output standard del lato sinistro all'estremità di scrittura del pipe e l'input standard del lato destro all'estremità di lettura. In alcune shell (ksh88, ksh93, zsh, bash con l' lastpipe
opzione impostata ed efficace), il lato destro viene eseguito nella shell originale, quindi il costrutto della pipeline crea solo una subshell.$(…)
(anche scritto `…`
) crea una subshell con l'output standard impostato su una pipe, raccoglie l'output nel padre e si espande a tale output, meno le sue nuove righe finali. (E l'output potrebbe essere ulteriormente soggetto a scissione e sconvolgimento, ma questa è un'altra storia.)<(…)
crea una subshell con l'output standard impostato su una pipe e si espande al nome della pipe. Il genitore (o qualche altro processo) può aprire la pipe per comunicare con la subshell. >(…)
fa lo stesso ma con la pipe su input standard.coproc …
crea una subshell e non attende che termini. L'input e l'output standard della subshell sono ciascuno impostato su una pipe con il genitore collegato all'altra estremità di ogni pipe.${...}
nella risposta?
command | { read line; … }
(a seconda della shell, line
potrebbe o non essere ancora disponibile dopo la pipeline). Tutti i modi coinvolgono una subshell perché il comando che produce l'output deve essere eseguito indipendentemente dalla shell che legge l'input. Se il comando è puramente interno alla shell (solo costrutti di shell e builtin, nessun comando esterno), la shell potrebbe non creare un sottoprocesso, ma si tratta solo di un'ottimizzazione, crea comunque una subshell.
Dalla pagina man bash (1) nella versione 4.4 di bash, sezione "EXPANSION", sottosezione "Sostituzione comandi":
Bash esegue l'espansione eseguendo
command
in un ambiente subshell [...]
bash
manpage non menziona alcuna subshell: Bash performs the expansion by executing command and replacing the command substitution with the standard output of the command, with any trailing newlines deleted.
mi chiedo se questa sia stata un'omissione deliberata.