Passer toutes les variables d’un script à un autre

Alors disons que j’ai un script shellscript / bash nommé test.sh

avec:

#!/bin/bash # TESTVARIABLE=hellohelloheloo ./test2.sh 

mon test2.sh ressemble à ceci

 #!/bin/bash # echo ${TESTVARIABLE} 

cela ne fonctionne pas. Je ne veux pas passer toutes les variables en tant que parameters, car à mon avis, cela est excessif. Y a-t-il une autre façon?

Vous avez essentiellement deux options:

  1. Faites de la variable une variable d’environnement ( export TESTVARIABLE ) avant d’exécuter le 2ème script.
  2. Source le 2ème script, c.-à-d . test2.sh . test2.sh et il s’exécutera dans le même shell. Cela vous permettrait de partager facilement des variables plus complexes comme les tableaux, mais cela signifie également que l’autre script pourrait modifier les variables du shell source.

METTRE À JOUR:

Pour utiliser l’ export pour définir une variable d’environnement, vous pouvez soit utiliser une variable existante:

 A=10 # ... export A 

Cela devrait fonctionner à la fois bash et sh . bash lui permet également de se combiner ainsi:

 export A=10 

Cela fonctionne aussi dans mon sh (qui se trouve être bash , vous pouvez utiliser echo $SHELL pour vérifier). Mais je ne pense pas que cela soit garanti de fonctionner dans tous les sh , alors mieux vaut le jouer en toute sécurité et les séparer.

Toute variable que vous exportez de cette manière sera visible dans les scripts que vous exécutez, par exemple:

cendre:

 #!/bin/sh MESSAGE="hello" export MESSAGE ./b.sh 

b.sh:

 #!/bin/sh echo "The message is: $MESSAGE" 

Alors:

 $ ./a.sh The message is: hello 

Le fait que ce soient deux scripts shell est également accessoire. Les variables d’environnement peuvent être transmises à n’importe quel processus que vous exécutez, par exemple si nous avons utilisé python à la place, cela pourrait ressembler à ceci:

cendre:

 #!/bin/sh MESSAGE="hello" export MESSAGE ./b.py 

b.py:

 #!/usr/bin/python import os print 'The message is:', os.environ['MESSAGE'] 

Sourcing:

Au lieu de cela, nous pourrions chercher comme ceci:

cendre:

 #!/bin/sh MESSAGE="hello" . ./b.sh 

b.sh:

 #!/bin/sh echo "The message is: $MESSAGE" 

Alors:

 $ ./a.sh The message is: hello 

Ceci plus ou moins “importe” le contenu de b.sh directement et l’exécute dans le même shell . Notez que nous n’avons pas eu à exporter la variable pour y accéder. Cela partage implicitement toutes les variables que vous avez, et permet à l’autre script d’append / supprimer / modifier des variables dans le shell. Bien sûr, dans ce modèle, vos deux scripts doivent avoir le même langage ( sh ou bash ). Donner un exemple de la manière dont nous pourrions transmettre des messages dans les deux sens:

cendre:

 #!/bin/sh MESSAGE="hello" . ./b.sh echo "[A] The message is: $MESSAGE" 

b.sh:

 #!/bin/sh echo "[B] The message is: $MESSAGE" MESSAGE="goodbye" 

Alors:

 $ ./a.sh [B] The message is: hello [A] The message is: goodbye 

Cela fonctionne aussi bien en bash . Cela facilite également le partage de données plus complexes que vous ne pouviez pas exprimer en tant que variable d’environnement (du moins sans vous soulever un peu de la main), comme les tableaux ou les tableaux associatifs.

Erreur fatale a donné une possibilité simple: source de votre deuxième script! Si vous craignez que ce second script ne modifie certaines de vos précieuses variables, vous pouvez toujours le rechercher dans un sous-shell:

 ( . ./test2.sh ) 

Les parenthèses feront apparaître la source dans un sous-shell, de sorte que le shell parent ne verra pas les modifications que test2.sh pourrait effectuer.


Il y a une autre possibilité qui devrait certainement être référencée ici: use set -a .

À partir de la référence de l’ set POSIX :

-a : Lorsque cette option est activée, l’atsortingbut d’ exportation doit être défini pour chaque variable à laquelle une affectation est effectuée; voir le volume Définitions de base de la norme IEEE 1003.1-2001, Section 4.21, Assignation des variables . Si l’affectation précède un nom d’utilitaire dans une commande, l’atsortingbut d’ exportation ne doit pas persister dans l’environnement d’exécution en cours après la fin de l’utilitaire, à l’exception du fait que l’un des utilitaires intégrés spéciaux entraîne la persistance de l’atsortingbut export dans a terminé. Si l’affectation ne précède pas un nom d’utilitaire dans la commande, ou si l’assignation résulte de l’opération des utilitaires getopts ou read , l’atsortingbut d’exportation doit persister jusqu’à ce que la variable soit désactivée.

Depuis le manuel de Bash :

-a : Marquer les variables et les fonctions qui sont modifiées ou créées pour l’exportation dans l’environnement des commandes suivantes.

Donc dans votre cas:

 set -a TESTVARIABLE=hellohelloheloo # ... # Here put all the variables that will be marked for export # and that will be available from within test2 (and all other commands). # If test2 modifies the variables, the modifications will never be # seen in the present script! set +a ./test2.sh # Here, even if test2 modifies TESTVARIABLE, you'll still have # TESTVARIABLE=hellohelloheloo 

Notez que les spécifications spécifient uniquement que, avec set -a la variable est marquée pour l’exportation. C’est:

 set -a a=b set +a a=c bash -c 'echo "$a"' 

va faire écho à c et non à une ligne vide ni à b (c’est-à-dire que set +a ne marque pas pour l’exportation, ni ne sauvegarde la valeur de l’affectation que pour l’environnement exporté). C’est bien sûr le comportement le plus naturel.

Conclusion: l’utilisation de set -a / set +a peut être moins fastidieuse que l’exportation manuelle de toutes les variables. Il est préférable de rechercher le deuxième script, car il fonctionnera pour toutes les commandes, pas seulement celles écrites dans le même langage de shell.

Il y a en fait un moyen plus simple que d’exporter et de désactiver ou de rechercher à nouveau (au moins en bash, tant que vous êtes d’accord pour transmettre les variables d’environnement manuellement):

laissez a.sh être

 #!/bin/bash secret="winkle my tinkle" echo Yo, lemme tell you \"$secret\", b.sh! Message=$secret ./b.sh 

et b.sh be

 #!/bin/bash echo I heard \"$Message\", yo 

La production observée est

[rob @ Archie test] $ ./a.sh
Yo, lemme te dire “winkle my tinkle”, b.sh!
J’ai entendu “winkle my tinkle”, yo

La magie se trouve dans la dernière ligne de a.sh , où Message , pour seulement la durée de l’invocation de ./b.sh , est défini sur la valeur de secret de a.sh En gros, c’est un peu comme les parameters / arguments nommés. De plus, cela fonctionne même pour des variables comme $DISPLAY , qui contrôle le serveur X sur lequel une application démarre.

Rappelez-vous que la longueur de la liste des variables d’environnement n’est pas infinie. Sur mon système avec un kernel relativement vanille, xargs --show-limits m’indique que la taille maximale du tampon d’arguments est de 2094486 octets. Théoriquement, vous utilisez des scripts shell erronés si vos données sont plus grandes que cela (pipes, n’importe qui?)

Dans Bash, si vous exportez la variable dans un sous-shell, en utilisant des parenthèses comme indiqué, vous évitez de divulguer les variables exscopes:

 #!/bin/bash TESTVARIABLE=hellohelloheloo ( export TESTVARIABLE source ./test2.sh ) 

L’avantage est que lorsque vous exécutez le script à partir de la ligne de commande, vous ne verrez pas de fuite de $ TESTVARIABLE dans votre environnement:

 $ ./test.sh hellohelloheloo $ echo $TESTVARIABLE #empty! no leak $ 

Ajouter à la réponse de l’erreur fatale, Il existe un autre moyen de transmettre les variables à un autre script de shell.

La solution proposée ci-dessus présente certains inconvénients:

  1. using Export : la variable sera hors de leur scope, ce qui n’est pas une bonne pratique de conception.
  2. using Source : cela peut provoquer des collisions de noms ou un remplacement accidentel d’une variable prédéfinie dans un autre fichier de script shell ayant généré un autre fichier.

Il existe une autre solution simple à notre disposition. Compte tenu de l’exemple que vous avez posté,

test.sh

 #!/bin/bash TESTVARIABLE=hellohelloheloo ./test2.sh "$TESTVARIABLE" 

test2.sh

 #!/bin/bash echo $1 

sortie

 hellohelloheloo 

Il est également important de noter que "" sont nécessaires si nous passons des chaînes multi-mots. Prenons un autre exemple

master.sh

 #!/bin/bash echo in master.sh var1="hello world" sh slave1.sh $var1 sh slave2.sh "$var1" echo back to master 

slave1.sh

 #!/bin/bash echo in slave1.sh echo value :$1 

slave2.sh

 #!/bin/bash echo in slave2.sh echo value : $1 

sortie

 in master.sh in slave1.sh value :"hello in slave2.sh value :"hello world" 

Cela se produit à cause des raisons bien décrites dans ce lien

Une autre façon, qui est un peu plus facile pour moi, consiste à utiliser des canaux nommés. Les canaux nommés permettent de synchroniser et d’envoyer des messages entre différents processus.

Rendre confus:

 #!/bin/bash msg="The Message" echo $msg > A.pipe 

B.bash:

 #!/bin/bash msg=`cat ./A.pipe` echo "message from A : $msg" 

Usage:

 $ mkfifo A.pipe #You have to create it once $ ./A.bash & ./B.bash # you have to run your scripts at the same time 

B.bash attend le message et dès que A.bash envoie le message, B.bash continue son travail.

Une autre option consiste à utiliser eval . Ceci ne convient que si les chaînes sont approuvées. Le premier script peut faire écho aux affectations de variables:

echo "VAR=myvalue"

Alors:

eval $(./first.sh) ./second.sh

Cette approche est particulièrement intéressante lorsque le deuxième script pour lequel vous souhaitez définir des variables d’environnement n’est pas en bash et que vous ne souhaitez pas non plus export les variables, peut-être parce qu’elles sont sensibles et que vous ne souhaitez pas qu’elles persistent.