104 votes

Définir une variable d'environnement dans un script Python

J'ai un script bash qui définit une variable d'environnement et exécute une commande

LD_LIBRARY_PATH=my_path
sqsub -np $1 /homedir/anotherdir/executable

Maintenant je veux utiliser python à la place de bash, car je veux calculer certains des arguments que je passe à la commande.

J'ai essayé

putenv("LD_LIBRARY_PATH", "my_path")

et

call("export LD_LIBRARY_PATH=my_path")

suivi de

call("sqsub -np " + var1 + "/homedir/anotherdir/executable")

mais le programme abandonne toujours car LD_LIBRARY_PATH n'est pas défini.

Comment puis-je résoudre ce problème?

Merci pour votre aide!

(si j'exporte LD_LIBRARY_PATH avant d'appeler le script python tout fonctionne, mais je voudrais que python détermine le chemin et définisse la variable d'environnement à la valeur correcte)

110voto

J.F. Sebastian Points 102961

Bash:

LD_LIBRARY_PATH=mon_chemin
sqsub -np $1 /chemin/vers/exécutable

Similaire, en Python:

import os
import subprocess
import sys

os.environ['LD_LIBRARY_PATH'] = "mon_chemin" # visible dans ce processus + tous les enfants
subprocess.check_call(['sqsub', '-np', sys.argv[1], '/chemin/vers/exécutable'],
                      env=dict(os.environ, SQSUB_VAR="visible dans ce sous-processus"))

23voto

Il y a de nombreuses bonnes réponses ici mais vous devriez éviter à tout prix de transmettre des variables non sécurisées à un sous-processus en utilisant shell=True car il s'agit d'un risque de sécurité. Les variables peuvent s'échapper vers le shell et exécuter des commandes arbitraires ! Si vous ne pouvez vraiment pas l'éviter, utilisez au moins shlex.quote() de python3 pour échapper la chaîne (si vous avez plusieurs arguments séparés par un espace, mettez des guillemets autour de chaque morceau au lieu de la chaîne entière).

shell=False est toujours la valeur par défaut lorsque vous passez un tableau d'arguments.

Maintenant les solutions sûres...

Méthode n°1

Modifiez l'environnement de votre propre processus - le nouvel environnement s'appliquera à Python lui-même et à tous les sous-processus.

os.environ['LD_LIBRARY_PATH'] = 'mon_chemin'
command = ['sqsub', '-np', var1, '/repertoire_personnel/autrerepertoire/executable']
subprocess.check_call(command)

Méthode n°2

Créez une copie de l'environnement et passez-la aux enfants. Vous avez un contrôle total sur l'environnement des enfants et cela n'affectera pas l'environnement de Python.

myenv = os.environ.copy()
myenv['LD_LIBRARY_PATH'] = 'mon_chemin'
command = ['sqsub', '-np', var1, '/repertoire_personnel/autrerepertoire/executable']
subprocess.check_call(command, env=myenv)

Méthode n°3

Uniquement sur Unix : Exécutez env pour définir la variable d'environnement. Plus contraignant si vous avez de nombreuses variables à modifier et non portable, mais comme la #2 vous conservez un contrôle total sur l'environnement de Python et des enfants.

command = ['env', 'LD_LIBRARY_PATH=mon_chemin', 'sqsub', '-np', var1, '/repertoire_personnel/autrerepertoire/executable']
subprocess.check_call(command)

Évidemment, si var1 contient plusieurs arguments séparés par des espaces, ils seront maintenant transmis en tant qu'un seul argument avec des espaces. Pour conserver le comportement d'origine avec shell=True, vous devez composer un tableau de commandes contenant la chaîne divisée :

command = ['sqsub', '-np'] + var1.split() + ['/repertoire_personnel/autrerepertoire/executable']

22voto

Manbeardo Points 53

Vous pouvez ajouter des éléments à votre environnement en utilisant

os.environ['LD_LIBRARY_PATH'] = 'mon_chemin'

et exécuter des sous-processus dans un shell (qui utilise votre os.environ) en utilisant

subprocess.call('sqsub -np ' + var1 + '/homedir/anotherdir/executable', shell=True)

-2voto

rdesgroppes Points 101

Solution compacte (à condition de ne pas avoir besoin d'autres variables d'environnement) :

subprocess.check_call(
    'sqsub -np {} /homedir/anotherdir/executable'.format(var1).split(),
    env=dict(LD_LIBRARY_PATH=my_path))

Utilisation de l'outil de ligne de commande env :

subprocess.check_call('env LD_LIBRARY_PATH=my_path sqsub -np {} /homedir/anotherdir/executable'.format(var1).split())

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