Quand «_» est-elle une variable d'environnement d'un shell bash?

10

Bash Manual dit (page de manuel, je souligne):

Lorsque Bash appelle une commande externe, la variable $_est définie sur le chemin d'accès complet de la commande et transmise à cette commande dans son environnement.

Et ( paramètres spéciaux ):

_

( $_, un trait de soulignement.) Au démarrage du shell, définissez le chemin d'accès absolu utilisé pour appeler le shell ou le script de shell en cours d'exécution tel que transmis dans l'environnement ou la liste d'arguments. Par la suite, se développe jusqu'au dernier argument de la commande précédente, après expansion. Définissez également le chemin d'accès complet utilisé pour appeler chaque commande exécutée et placée dans l'environnement exporté vers cette commande. Lors de la vérification du courrier, ce paramètre contient le nom du fichier courrier.

  1. Dans un shell bash, je lance:

    $ bash
    $ export | grep '_=' 

    Selon le manuel, _devrait être une variable d'environnement du nouveau shell bash. exportest censé sortir toutes les variables d'environnement du nouveau shell bash, mais il ne sort pas _. Je me demande donc si _est une variable d'environnement du nouveau shell bash?

  2. En fait, dans n'importe quel shell bash, la même chose se produit

    $ export | grep '_='

    ne produit rien. Je me demande donc s'il _existe jamais une variable d'environnement d'un shell bash?

  3. En comparaison:

    $ dash
    $ export  | grep '_='        
    export _='/bin/dash'

Mon message est inspiré du commentaire de Mike et de la réponse de Stéphane .

Tim
la source
1
C'est une variable shell, et elle est passée à l' environnement de la commande ; il n'est pas nécessairement exporté vers l' environnement du shell . exportest une fonction intégrée, mais si vous l'utilisez printenv _, elle vous montrera comment elle a été invoquée: /usr/bin/printenvsur ce système.
Toby Speight
Notez que bash -c export | grep _=(Bash), va montrer comment le shell parent a invoqué la bashcommande, même si $_est dans le parent unset.
Toby Speight

Réponses:

13

Oui, _est une variable d'environnement du nouveau shell Bash; vous pouvez le voir en exécutant

tr '\0' '\n' < /proc/$$/environ | grep _=

à l'intérieur du shell: qui montre le contenu de l'environnement initial du shell. Vous ne le verrez pas dans le premier shell car il n'y avait pas de shell précédent pour le définir avant de commencer.

Le développement à l' $_intérieur de Bash fait référence au _paramètre spécial, qui se développe jusqu'au dernier argument de la commande précédente. (En interne, Bash gère cela en utilisant une _variable shell, qui est mise à jour chaque fois qu'une commande est analysée, mais c'est vraiment un détail d'implémentation. Elle est "non exportée" chaque fois qu'une commande est analysée. ) exportNe s'affiche pas _parce qu'elle n'est pas une variable qui est marquée comme exportée; vous pouvez cependant le voir dans la sortie de set.

Dans le premier exemple, le nouveau shell Bash analyse et exécute les commandes dans ses fichiers de démarrage, donc lors de son exécution explore | grep '-=', il _a déjà été remplacé et marqué comme non exporté.

Dans l' dashexemple, il ne semble pas exécuter de fichier de démarrage, vous voyez donc la variable comme une variable d'environnement qui a été définie par Bash avant de s'exécuter dash.

Stephen Kitt
la source
Merci. Dans le nouveau shell bash, pourquoi ne export | grep '_='produit-il rien? Dans le shell bash d'origine, pourquoi ne tr '\0' '\n' < /proc/$$/environ | grep _=produit-il rien?
Tim
9

exportsans arguments répertorie toutes les variables exportées . _n'est pas une variable, mais est répertorié comme paramètre spécial .

Un peu confus, _serait également un nom valide pour une variable , contrairement aux noms des autres paramètres spéciaux. Au moins Bash 4.4 permet des affectations, sans plaintes. Ce n'est tout simplement pas utile car l'effet spécial remplace immédiatement la valeur.

ilkkachu
la source
2
Amusez-vous bien à essayer de l'utiliser _comme variable ;-). Il est effectivement en écriture seule et la valeur est immédiatement perdue.
Stephen Kitt
1
De plus, en interne, Bash traite _comme une variable, c'est pourquoi il apparaît dans la sortie de set. Cependant, il ne peut pas être marqué comme exporté pour autant que je puisse le déterminer.
Stephen Kitt
2
@StephenKitt, mais Bash 4.4 permet de le marquer en lecture seule. Ou un entier. Avec des résultats quelque peu hilarants.
ilkkachu
1
Ha, belle trouvaille, c'est plutôt amusant!
Stephen Kitt
5

Toutes les variables shell ne sont pas marquées comme exportées comme vous pouvez le voir dans la sortie de declare -p.

Cela n'a aucun sens bashde marquer $_comme exporté car il ajoute automatiquement cette variable à l'environnement des processus enfants mais avec une valeur différente de celle qu'il a dans le shell (à ce moment).

L'afficher comme exporté ne ferait que dérouter l'utilisateur sur ce qui va se passer avec l'environnement des commandes externes.

Toutes les "variables d'exécution" BASH*ne sont pas exportées.

Hauke ​​Laging
la source