$(…)est un sous-shell par définition: il s'agit d'une copie de l'état d'exécution du shell¹, et les modifications apportées à l'état dans le sous-shell n'ont aucun impact sur le parent. Un sous-shell est généralement implémenté en recourant à un nouveau processus (mais certains shells peuvent l'optimiser dans certains cas).
Ce n'est pas un sous-shell à partir duquel vous pouvez récupérer des valeurs de variables. Si les modifications apportées aux variables ont un impact sur le parent, il ne s'agira pas d'un sous-shell. C'est un sous-shell dont le parent peut récupérer la sortie . La $(…)sortie standard du sous-shell créé par est définie sur un canal, et le parent lit ce canal et collecte la sortie.
Plusieurs autres constructions créent un sous-shell. Je pense que ceci est la liste complète pour bash:
Sous-shell pour le groupement : ( … )ne crée qu'un sous-shell et attend sa fin). Contraste avec { … }lequel le groupe commande uniquement à des fins syntaxiques et ne crée pas de sous-shell.
Background : … &crée un sous-shell et n'attend pas sa fin.
Pipeline : … | …crée deux sous-réservoirs, un pour le côté gauche et un pour le côté droit, et attend la fin des deux. Le shell crée un tuyau et connecte la sortie standard du côté gauche à l'extrémité écriture du tuyau et l'entrée standard du côté droit à l'extrémité lecture. Dans certains shells (ksh88, ksh93, zsh, bash avec les lastpipeoptions set et effective), le côté droit s'exécute dans le shell d'origine, de sorte que la construction de pipeline ne crée qu'un seul sous-shell.
Substitution de commande : $(…)(également orthographié `…`) crée un sous-shell dont la sortie standard est définie sur un tuyau, collecte la sortie dans le parent et se développe jusqu'à cette sortie, moins les nouvelles lignes. (Et la sortie peut être davantage sujette à la scission et à l'effacement, mais c'est une autre histoire.)
Substitution de processus : <(…)crée un sous-shell avec sa sortie standard définie sur un tuyau et se développe au nom du tuyau. Le parent (ou un autre processus) peut ouvrir le canal pour communiquer avec le sous-shell. >(…)fait la même chose mais avec le tuyau sur l'entrée standard.
Coprocess : coproc …crée un sous-shell et n'attend pas qu'il se termine. L'entrée et la sortie standard du sous-shell sont définies sur un tuyau, le parent étant connecté à l'autre extrémité de chaque tuyau.
Pourriez-vous également inclure ${...}dans la réponse?
user1717828
3
@ user1717828 Quoi? Pourquoi? Qu'est-ce que l'expansion variable à distance a à voir avec cette question? Je ne vais pas inclure tout le manuel du shell dans ma réponse.
Gilles, arrête de faire le mal
1
Qu'est-ce que l'expansion variable à distance a à voir avec cette question? Je ne sais pas, c'est pourquoi j'ai demandé :-) Donc, je suppose que la substitution d'accolade n'a rien à voir avec la substitution d'accolade entre parenthèses.
user1717828
@ user1717828: le développement de variable n'est pas lié aux sous-shell; c'est un mécanisme à part entière, et il vaut vraiment la peine de l'explorer si vous débutez!
0xdd
1
@ EnricoMariaDeAngelis Ce n'est pas le seul moyen, mais c'est le moyen le plus naturel. Une autre méthode est command | { read line; … }(selon le shell, linepeut ou peut ne pas être encore disponible après le pipeline). Tous les moyens impliquent un sous-shell car la commande qui produit la sortie doit s'exécuter indépendamment du shell qui lit l'entrée. Si la commande est purement interne au shell (uniquement les constructions et les commandes intégrées du shell, pas de commandes externes), le shell peut ne pas créer de sous-processus, mais il ne s'agit que d'une optimisation, il crée toujours un sous-shell.
Gilles, arrête d'être méchant
20
Dans la page de manuel bash (1) de la version 4.4, la section "EXPANSION", la sous-section "Substitution de commande" de bash:
Bash effectue l'expansion en s'exécutant commanddans un environnement de sous-shell [...]
Fait intéressant, sous CentOS 7, la bashpage de manuel ne mentionne aucun sous-shell: Bash performs the expansion by executing command and replacing the command substitution with the standard output of the command, with any trailing newlines deleted.je me demande s’il s’agissait d’une omission délibérée.
dr01
6
@ dr01 Au contraire, bash 4.4 a modifié le libellé de cette phrase pour inclure le mot "subshell". C'était une clarification: le manuel mentionnait explicitement que divers autres constructs étaient des sous-shell, mais jusqu'à la version 4.4, cela n'était pas explicitement indiqué pour la substitution de commande.
Gilles, arrête de faire le mal
Oui, sur CentOS v7.4.1708 (assez récent) bash est v4.2.46.
dr01
5
Oui, ( commands... )est un bashsous-shell qui s'exécutera commands...dans un autre processus.
La seule différence que vous avez $( commands... )est que cette partie du code, après exécution, commands...sera remplacée par tout ce qui a été commands...écrit stdout.
Réponses:
$(…)
est un sous-shell par définition: il s'agit d'une copie de l'état d'exécution du shell¹, et les modifications apportées à l'état dans le sous-shell n'ont aucun impact sur le parent. Un sous-shell est généralement implémenté en recourant à un nouveau processus (mais certains shells peuvent l'optimiser dans certains cas).Ce n'est pas un sous-shell à partir duquel vous pouvez récupérer des valeurs de variables. Si les modifications apportées aux variables ont un impact sur le parent, il ne s'agira pas d'un sous-shell. C'est un sous-shell dont le parent peut récupérer la sortie . La
$(…)
sortie standard du sous-shell créé par est définie sur un canal, et le parent lit ce canal et collecte la sortie.Plusieurs autres constructions créent un sous-shell. Je pense que ceci est la liste complète pour bash:
( … )
ne crée qu'un sous-shell et attend sa fin). Contraste avec{ … }
lequel le groupe commande uniquement à des fins syntaxiques et ne crée pas de sous-shell.… &
crée un sous-shell et n'attend pas sa fin.… | …
crée deux sous-réservoirs, un pour le côté gauche et un pour le côté droit, et attend la fin des deux. Le shell crée un tuyau et connecte la sortie standard du côté gauche à l'extrémité écriture du tuyau et l'entrée standard du côté droit à l'extrémité lecture. Dans certains shells (ksh88, ksh93, zsh, bash avec leslastpipe
options set et effective), le côté droit s'exécute dans le shell d'origine, de sorte que la construction de pipeline ne crée qu'un seul sous-shell.$(…)
(également orthographié`…`
) crée un sous-shell dont la sortie standard est définie sur un tuyau, collecte la sortie dans le parent et se développe jusqu'à cette sortie, moins les nouvelles lignes. (Et la sortie peut être davantage sujette à la scission et à l'effacement, mais c'est une autre histoire.)<(…)
crée un sous-shell avec sa sortie standard définie sur un tuyau et se développe au nom du tuyau. Le parent (ou un autre processus) peut ouvrir le canal pour communiquer avec le sous-shell.>(…)
fait la même chose mais avec le tuyau sur l'entrée standard.coproc …
crée un sous-shell et n'attend pas qu'il se termine. L'entrée et la sortie standard du sous-shell sont définies sur un tuyau, le parent étant connecté à l'autre extrémité de chaque tuyau.¹ Au lieu d’exécuter un shell séparé .
la source
${...}
dans la réponse?command | { read line; … }
(selon le shell,line
peut ou peut ne pas être encore disponible après le pipeline). Tous les moyens impliquent un sous-shell car la commande qui produit la sortie doit s'exécuter indépendamment du shell qui lit l'entrée. Si la commande est purement interne au shell (uniquement les constructions et les commandes intégrées du shell, pas de commandes externes), le shell peut ne pas créer de sous-processus, mais il ne s'agit que d'une optimisation, il crée toujours un sous-shell.Dans la page de manuel bash (1) de la version 4.4, la section "EXPANSION", la sous-section "Substitution de commande" de bash:
la source
bash
page de manuel ne mentionne aucun sous-shell:Bash performs the expansion by executing command and replacing the command substitution with the standard output of the command, with any trailing newlines deleted.
je me demande s’il s’agissait d’une omission délibérée.Oui,
( commands... )
est unbash
sous-shell qui s'exécuteracommands...
dans un autre processus.La seule différence que vous avez
$( commands... )
est que cette partie du code, après exécution,commands...
sera remplacée par tout ce qui a étécommands...
écritstdout
.la source