3 votes

Une fonction Bash échoue lorsqu'elle fait partie d'un pipe

Il s'agit d'une tentative de simplification d'un problème que je rencontre. Je définis une fonction qui définit une variable et cela fonctionne dans ce scénario :

$ function myfunc { res="ABC" ; }
$ res="XYZ"
$ myfunc
$ echo $res
    ABC

Ainsi, res a été modifié par l'appel à myfunc. Mais :

$ res="XYZ"
$ myfunc | echo
$ echo $res
    XYZ

Ainsi, lorsque myfunc fait partie d'un pipe, la valeur ne change pas. Comment puis-je faire en sorte que myfunc fonctionne comme je le souhaite même lorsqu'un pipe est impliqué ?

(Dans le vrai script "myfunc" fait quelque chose de plus élaboré bien sûr et l'autre côté du tuyau a un dialogue de progrès zenity plutôt qu'un écho inutile).

Remerciements

4voto

Aaron Digulla Points 143830

Cela n'est pas possible sous Unix. Pour mieux comprendre, il faut savoir ce qu'est une variable. Bash conserve deux tables internes contenant toutes les variables définies. L'une d'entre elles contient les variables locales à l'interpréteur de commandes actuel. Vous pouvez les créer avec set name=value ou simplement name=value . Elles sont locales au processus ; elles ne sont pas héritées lors de la création d'un nouveau processus.

Pour exporter une variable vers de nouveaux processus enfants, vous devez l'exporter avec l'option export name . Cela dit à bash "Je veux que les enfants voient la valeur de cette variable". C'est une mesure de sécurité.

Lorsque vous invoquez une fonction en bash, elle est exécutée dans le contexte de l'interpréteur de commandes actuel, ce qui lui permet d'accéder à toutes les variables et de les modifier.

Mais un tuyau est une liste de processus qui sont connectés avec des tuyaux d'entrée/sortie. Cela signifie que votre fonction est exécutée dans un shell et que seule la sortie de ce shell est visible par echo .

Même l'exportation en myfunc ne fonctionnerait pas parce que l'exportation ne fonctionne que pour les processus lancés par le shell où vous avez effectué l'exportation et que echo a été lancé par le même shell que myfunc :

bash
 +-- myfunc
 +-- echo

c'est-à-dire echo n'est pas un enfant de myfunc .

Solutions de contournement :

  1. Écriture de la variable dans un fichier
  2. Utilisez un format de sortie plus complexe comme XML ou plusieurs lignes où la première ligne de sortie est toujours la variable et la vraie sortie vient dans la ligne suivante.

4voto

Gordon Davisson Points 22534

Comme @Aaron l'a dit, le problème est dû au fait que la fonction s'exécute dans un sous-shell. Mais il y a un moyen d'éviter cela dans bash, en utilisant la substitution de processus au lieu d'un pipe :

myfunc > >(echo)

Cela fait à peu près la même chose qu'un pipe, mais myfunc s'exécute dans le shell principal plutôt que dans un sous-processus. Notez qu'il s'agit d'une fonctionnalité bash uniquement, et que vous devez doit utilisez #!/bin/bash comme shebang pour que cela fonctionne.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X