web-dev-qa-db-fra.com

Pourquoi les variables d'environnement définies en python ne peuvent-elles pas persister?

J'espérais écrire un script python pour créer des variables d'environnement appropriées en l'exécutant dans le répertoire dans lequel j'exécuterais du code de simulation, et j'ai lu que je ne peux pas écrire de script pour faire en sorte que ces variables d'environnement persistent dans le terminal mac os. Donc deux choses:

Est-ce vrai?

et

Il semble que ce serait une chose utile à faire. pourquoi n'est-ce pas possible en général?

37
physicsmichael

Vous ne pouvez pas le faire à partir de python, mais quelques astuces de bash peuvent faire quelque chose de similaire. Le raisonnement de base est le suivant: les variables d’environnement existent dans un espace mémoire par processus. Lorsqu'un nouveau processus est créé avec fork (), il hérite des variables d'environnement de son parent. Lorsque vous définissez une variable d'environnement dans votre shell (par exemple, bash), procédez comme suit: 

export VAR="foo"

Ce que vous faites, c'est dire à bash de définir la variable VAR dans son espace processus sur "foo". Lorsque vous exécutez un programme, bash utilise fork () puis exec () pour l'exécuter. Ainsi, tout ce que vous exécutez à partir de bash hérite des variables d'environnement bash. 

Supposons maintenant que vous souhaitiez créer une commande bash qui définisse une variable d'environnement DATA avec le contenu d'un fichier de votre répertoire actuel appelé ".data". Tout d'abord, vous devez avoir une commande pour extraire les données du fichier: 

cat .data

Cela imprime les données. Maintenant, nous voulons créer une commande bash pour définir ces données dans une variable d’environnement: 

export DATA=`cat .data`

Cette commande prend le contenu de .data et le met dans la variable d'environnement DATA. Maintenant, si vous mettez cela dans une commande d'alias, vous avez une commande bash qui définit votre variable d'environnement:

alias set-data="export DATA=`cat .data`"

Vous pouvez insérer cette commande alias dans les fichiers .bashrc ou .bash_profile de votre répertoire personnel pour que cette commande soit disponible dans tout nouveau shell bash que vous démarrez. 

31
Benson

Une solution de contournement consiste à générer les commandes export et à demander au shell parent de l'évaluer.

thescript.py:

import pipes
import random
r = random.randint(1,100)
print("export BLAHBLAH=%s" % (pipes.quote(str(r))))

..et le bash alias (la même chose peut être faite dans la plupart des coquillages .. même tcsh!):

alias setblahblahenv="eval $(python thescript.py)"

Usage:

$ echo $BLAHBLAH

$ setblahblahenv
$ echo $BLAHBLAH
72

Vous pouvez générer n'importe quel code Shell, y compris plusieurs commandes telles que:

export BLAHBLAH=23 SECONDENVVAR='something else' && echo 'everything worked'

Rappelez-vous simplement de ne pas échapper à une sortie créée dynamiquement (le module pipes.quote convient à cela)

17
dbr

Si vous définissez des variables d'environnement dans un script Python (ou tout autre script ou programme), cela n'affectera pas le Shell parent.

Clarifiez la clarification: Ainsi, la réponse à votre question est oui, c’est vrai… .Vous pouvez toutefois exporter à partir d’un script Shell et le générer à l’aide de l’appel de points.

dans fooexport.sh

export FOO="bar"

à l'invite de commande

$ . ./fooexport.sh
$ echo $FOO
bar
3
Stefano Borini

Ce que j'aime faire, c'est utiliser/usr/bin/env dans un script Shell pour "boucler" ma ligne de commande lorsque je me trouve dans des situations similaires:

#!/bin/bash

/usr/bin/env NAME1="VALUE1" NAME2="VALUE2" ${*}

Appelons donc ce script "myappenv". Je le mets dans mon répertoire $ HOME/bin que j'ai dans mon $ PATH.

Maintenant, je peux appeler n'importe quelle commande utilisant cet environnement en ajoutant simplement "myappenv" comme suit:

myappenv dosometask -xyz

Les autres solutions affichées fonctionnent aussi, mais c'est ma préférence personnelle. L'un des avantages est que l'environnement est transitoire. Ainsi, si je travaille dans le shell, seule la commande que j'appelle est affectée par l'environnement modifié.

Version modifiée basée sur les nouveaux commentaires

#!/bin/bash

/usr/bin/env G4WORKDIR=$PWD ${*}

Vous pouvez aussi envelopper tout cela dans un alias. Je préfère l'approche du script wrapper car j'ai tendance à intégrer d'autres préparations d'environnement, ce qui me facilite la maintenance.

2
Joe Holloway

Ce n'est généralement pas possible. Le nouveau processus créé pour Python ne peut pas affecter l'environnement de son processus parent. Le parent ne peut pas non plus affecter l'enfant, mais ce dernier doit configurer l'environnement de l'enfant dans le cadre de la création d'un nouveau processus.

Peut-être pouvez-vous les définir dans le script .bashrc, .profile ou l'équivalent "s'exécute à la connexion" ou "s'exécute à chaque nouvelle session de terminal" dans MacOS.

Vous pouvez également demander à python de démarrer le programme de simulation avec l’environnement souhaité. (utilisez le paramètre env pour subprocess.Popen ( http://docs.python.org/library/subprocess.html ))

import subprocess, os
os.chdir('/home/you/desired/directory')
subprocess.Popen(['desired_program_cmd', 'args', ...], env=dict(SOMEVAR='a_value') )

Vous pouvez également demander à python d’écrire un script Shell comme celui-ci dans un fichier avec une extension .sh

export SOMEVAR=a_value
cd /home/you/desired/directory
./desired_program_cmd

puis chmod +x et exécutez-le de n’importe où.

1
Joe Koberg

Comme le lui a répondu Benson, le mieux est de créer une simple fonction bash pour préserver les arguments:

upsert-env-var (){ eval $(python upsert_env_var.py $*); }

Vous pouvez faire ce que vous voulez dans votre script python avec les arguments. Pour ajouter simplement une variable, utilisez quelque chose comme:

var = sys.argv[1]
val = sys.argv[2]
if os.environ.get(var, None):
    print "export %s=%s:%s" % (var, val, os.environ[var])
else:
    print "export %s=%s" % (var, val)

Usage:

upsert-env-var VAR VAL
0
Niall