Il est possible de changer l'environnement bash en "sourçant" un script bash. Mais comment ça se passe si on veut le faire avec un script python ?
Petit rappel
Sous unix, chaque processus s'exécute dans un contexte particulier. Une des 'caractéristiques' de ce contexte est l'environnement d'exécution représenté par les variables d'environnement. Chaque processus (excepté le premier, init) est lancé par un autre processus (le processus père) et hérite d'une copie de l'environnement de ce dernier.
Comme le processus fils accède à une copie de l'environnement du processus père, il ne peut pas le modifier. Ainsi, sous bash, si vous exécutez un programme (ou un script), à la sortie de ce script, l'environnement du processus père (votre terminal ici) n'est pas modifié. Par contre, si vous interprétez le script dans le processus courant à l'aide de l'instruction source, l'environnement du processus est modifié (notez bien qu'il n'y a pas de processus père ou fils, car il n'y a qu'un seul processus)
Prenez ce script simple que nous appellerons essai.sh (oui, je sais, ce n'est pas très imaginatif mais bon, ce n'est pas le but de ce billet) :
echo "variable TRUC : $TRUC" echo "modification de la variable denvironnement TRUC" export TRUC="machin" echo "variable TRUC après modification : $TRUC"
$ export TRUC="bidule" $ echo $TRUC bidule $ ./essai.sh variable TRUC : bidule modification de la variable denvironnement TRUC variable TRUC après modification : machin $ echo $TRUC bidule $ source essais.sh variable TRUC : bidule modification de la variable denvironnement TRUC variable TRUC après modification : machin $ echo $TRUC machin
#!/usr/bin/env python #-*- coding:utf-8 -*- import os print "variable TRUC :",os.getenv("TRUC") print "modification de la variable denvironnement TRUC" os.environ["TRUC"]="machin" print "variable TRUC après modification :",os.getenv("TRUC")
#!/usr/bin/env python #-*- coding:utf-8 -*- # Pour éviter les conflits de nom, on sauvegarde l'espace de nom global avant qu'il ne soit "pollué" par nos variables. __globals__ = dict(globals()) # dump_env s'occupe de traduire l'environnement python en instructions bash. def dump_env(dumpOutput): import os for key in os.environ: dumpOutput.write('export %(key)s="%(value)s";\n'%{'key':key,'value':os.environ[key]}) if __name__=="__main__": import sys import os # On redéfinie la sortie standard. Ainsi le script utilisateur fera ses "print" sur le descripteur de fichier 3 et on imprimera l'environnement sur le descripteur de fichier 1 dumpOutput=sys.stdout sys.stdout=os.fdopen(3,'w') # On modifie quelques variables pour que le script utilisateur n'est pas conscience de pylauncher.py __globals__['__file__'] = sys.argv[1] sys.argv=sys.argv[1:] try: # On exécute le script utilisateur. # On redéfinie les espaces de nom globaux et locaux pour les mêmes raisons que le commentaire précédent. # On n'utilise pas os.system ou subprocess, car justement, on ne veut pas d'un processus fils. execfile est l'équivalent d'un source, mais à la mode python. execfile(sys.argv[0], __globals__, dict()) # On imprime l'environnement. dump_env(dumpOutput) except IOError: print(sys.exc_info()[1])
#!/bin/bash line="./pylauncher.py $@" # On initialise le descripteur de fichier 3. exec 3>&1 # À ce moment on a trois descripteurs de fichier ouverts : # - le numéro 1 qui pointe vers la sortie standard. (là où sont imprimées les instructions bash) # - le numéro 2 qui pointe vers la sortie d'erreur. # - le numéro 3 qui pointe vers la sortie standard. (là où sont imprimées les sorties standard du script utilisateur) # On lance pylauncher.py qui va lancer le script utilisateur et on évalue les instructions bash pour retrouver l'environnement modifier par le script utilisateur eval `$line` # On ferme le descripteur de fichier 3.;; exec 3>&-
$ ls pylauncher.py essai.py $ export TRUC="bidule" $ source sourcepy.sh essai.py # ou sourcepy essai.py si on a fait une fonction sourcepy variable TRUC : bidule modification de la variable denvironnement TRUC variable TRUC après modification : machin $ echo $TRUC machin
Et voilà !
PS J'ai volontairement enlever l'apostrophe à "l'environnement" pour éviter une coloration syntaxique foireuse.
Commentaires
Poster un nouveau commentaire