Différence entre expansion et substitution dans la terminologie de script shell

8

L'expansion et la substitution semblent être interchangeables dans le même contexte dans le langage de programmation shell. Par exemple, certains documents tels que le manuel de référence Bash , Bash Hackers Wiki utilisent le mot «expansion» pour expliquer « expansion des paramètres du shell ». Cependant, certains autres documents semblent préférer le mot «substitution». Le Guide avancé de Bash-Scripting utilise la substitution de paramètres .

Existe-t-il une différence entre «expansion» et «substitution» en termes de terminologie de programmation shell?

MS.Kim
la source
Les deux sont valables dans des contextes différents, par exemple variable expansion, command substitution. Quel est ton doute?
devnull
Sans contexte spécifique, je crains que ce soit trop large et pas trop clair .
devnull
En regardant la page de manuel de bash, en général, le mot "expansion" semble être utilisé si seuls des éléments internes au shell sont impliqués, tandis que la "substitution" semble être préférée pour les choses impliquant des processus externes.
celtschk
Si vous suivez mon conseil, vous arrêterez de lire ces documents jusqu'à ce que vous les connaissiez complètement: pubs.opengroup.org/onlinepubs/9699919799/utilities/… Lorsque vous aurez terminé avec ceux que vous faites man shet man set. Et quand vous avez ces informations, vous faites les documents spécifiques au shell.
mikeserv
@devnull Vous avez raison. Bien que je mette le lien pour le contexte, il serait préférable de spécifier explicitement le contexte avec question. Je vais modifier la question afin que les gens puissent la comprendre clairement.
MS.Kim

Réponses:

6

La substitution est presque synonyme d' expansion dans ce contexte parce que leurs significations se chevauchent. Aucune des deux n'est une sous-catégorie tout à fait complète de l'autre, bien que dans la section GNU Manual que vous mentionnez, il existe des substitutions qui sont considérées comme faisant partie d'une expansion globale.

Une expansion extrait la valeur d'un identifiant. Par exemple, si this=that, lorsque nous nous développons, thisnous obtenons that. Une expansion qui n'implique pas de substitution est prédéterminée en ce que la valeur utilisée existe déjà et doit simplement être récupérée, bien que cela comprenne la combinaison de valeurs récupérées / explicites (comme avec une "expansion arithmétique").

Une substitution crée une valeur à la suite d'une opération d'entrée / sortie explicite. Par exemple, si this=$(foo bar), thisest le résultat de l'exécution foo baret de la capture de sa sortie. 1 Bien que la valeur résultant d'une substitution puisse être complètement prévisible, elle est différente de celle récupérée dans une expansion normale car elle n'existe réellement que lorsque la substitution a lieu - elle est produite.

Les substitutions se présentent sous deux formes, commande et processus , qui sont en quelque sorte symétriques:

# Command substitution
foo=$(ls)
# Process substitution
wc <(ls)

La "commande" dans la première est ls, tout comme le "processus" dans la seconde. On pourrait dire que ce qui est substitué est vraiment la fin d'un tuyau. La substitution de processus chevauche la redirection . Cependant, c'est probablement un peu trop restrictif techniquement, ce qui nous amène à la note de bas de page ...


  1. foo bardans ce cas, il pourrait s'agir d'une fonction de shell interne, auquel cas il n'y a pas d'E / S interprocessus. L'existence de modules intégrés au shell obscurcit moins évidemment cette différence. En termes de contenu, l'entrée et la sortie seront les mêmes.
boucle d'or
la source
J'aime cette explication, mais comment la mettre en carré avec l' expansion du nom de fichier , qui produit certainement un ensemble de noms de fichiers à la suite d'une opération (un algorithme de correspondance).
De Novo
Bien sûr, mais pour jouer la sémantique, "extraire la valeur d'un identifiant" (ce que j'ai appelé une expansion) n'est-il pas aussi une opération, donc une substitution? D'autant plus que "certaines substitutions sont considérées comme faisant partie d'une expansion globale". C'est-à-dire que la relation entre ces mots n'est pas analogue à la distinction entre gauche et droite. Je pense que l'expansion du nom de fichier correspond bien à ma définition originale de l'expansion, mais j'ai clarifié les choses sur les substitutions ci-dessus pour aider à rendre plus évident pourquoi ce n'est pas le cas.
goldilocks
Le problème que j'ai eu en quadrillant cette explication autrement intuitive avec l'expansion du nom de fichier n'était pas que je voulais que les termes soient définis exclusivement, mais que l'expansion du nom de fichier ne semble pas récupérer une valeur liée à un identifiant. Dans un shell donné, la valeur d'un glob donné dépendrait de plus que du glob, et le même glob pourrait produire des sorties différentes dans des contextes différents. De plus, il n'est pas nécessaire de lier la valeur pour la récupérer ultérieurement. La relation n'est pas arbitraire (comme dans foo = "ce que vous voulez"; echo "$ foo"), mais plutôt le calcul et le résultat.
De Novo
Je suppose que la relation entre l'expression et la valeur dans l'expansion arithmétique n'est pas (exactement) arbitraire non plus, mais il n'y a certainement qu'une seule valeur pour une expansion donnée, quel que soit le contexte. Je suis peut-être en train de tergiverser ici, mais de toutes les extensions de shell, l'expansion du nom de fichier semble être l'homme étrange, compte tenu de cette explication.
De Novo
2
set -- arg arg2
echo ${2+"$1"}
 #OUTPUT 
arg

shift
echo ${2+"$1"}
 #OUTPUT

 #there doesn't seem to be anything here

Je pense que la différence est généralement trop minime pour être digne de mention - et les termes sont souvent utilisés de manière interchangeable. Cependant, si vous regardez les deux cas ci-dessus, vous pouvez voir que dans le premier exemple, nous nous substituons $1 à $2la suite de l' expansion de $2. Dès qu'il $2ne peut être étendu, il n'y a pas de substitution.

goldilocks fait un bon point sur l'existence éthérée des substitutions. Un peu comme le chat de Schrodinger, je suppose. Cela m'a rappelé quelque chose. Vous ne connaissez peut-être pas cette forme d'extension de paramètres spécifiée par POSIX, mais elle fonctionne d'une manière opposée à la forme ci-dessus:

${var:?if $var is unset or null its \
     parent shell dies and this message is output to stderr}

Maintenant, parfois, je veux le même comportement mais pour une setvaleur. POSIX ne spécifie pas exactement ce comportement. Mais, avec une ou deux astuces, c'est simplement géré:

N= #N is null
var="any value should fail"
${var:+${N:?we substitute our \$Null var when \$var is expanded}}
  #OUTPUT
sh: line 3: N: we substitute our $Null var when $var is expanded

Mais:

N= #N is null
var=
${var:+${N:?is never substituted}}
  #OUTPUT

#there doesn't seem to be anything here
mikeserv
la source