$ () È una subshell?


Risposte:


75

$(…)è 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:

  • Sotto-shell per il raggruppamento : ( … )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.
  • Sfondo : … &crea una subshell e non aspetta che termini.
  • Pipeline : … | …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' lastpipeopzione impostata ed efficace), il lato destro viene eseguito nella shell originale, quindi il costrutto della pipeline crea solo una subshell.
  • Sostituzione del comando : $(…)(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.)
  • Sostituzione del processo : <(…)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.
  • Coprocesso : 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.

¹ Invece di eseguire una shell separata .


Potresti includere anche ${...}nella risposta?
user1717828

3
@ user1717828 Cosa? Perché? Che cosa ha a che fare l'espansione variabile da remoto con questa domanda? Non includerò l'intero manuale della shell nella mia risposta.
Gilles 'SO- smetti di essere malvagio'

1
Che cosa ha a che fare l'espansione variabile da remoto con questa domanda? Non lo so, ecco perché ho chiesto :-) Quindi suppongo che la sostituzione della parentesi graffa non assomigli alla sostituzione della parentesi.
user1717828

@ user1717828: l'espansione variabile non è correlata ai subshells; è un meccanismo completamente separato, e sicuramente vale la pena leggere se hai appena iniziato!
0xdd,

1
@EnricoMariaDeAngelis Non è l'unico modo, ma è il modo più naturale. Un altro modo è command | { read line; … }(a seconda della shell, linepotrebbe 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.
Gilles 'SO- smetti di essere malvagio' il

20

Dalla pagina man bash (1) nella versione 4.4 di bash, sezione "EXPANSION", sottosezione "Sostituzione comandi":

Bash esegue l'espansione eseguendo commandin un ambiente subshell [...]



1
È interessante notare che in CentOS 7 la bashmanpage 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.
dr01,

6
@ dr01 Al contrario, bash 4.4 ha modificato il testo di quella frase per includere la parola "subshell". Era un chiarimento: il manuale menzionava esplicitamente che vari altri costrutti erano sottotitoli, ma fino al 4.4 non era esplicitamente dichiarato per la sostituzione dei comandi.
Gilles 'SO- smetti di essere malvagio'

Sì, su CentOS v7.4.1708 (abbastanza recente) bash è v4.2.46.
dr01,

5

Sì, ( commands... )è una bashsubshell che verrà eseguita commands...in un altro processo.

L'unica differenza quando hai $( commands... )è che questa parte di codice dopo l'esecuzione commands...verrà sostituita con tutto ciò che ha commands...scritto stdout.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.