Python subprocess / Popen avec un environnement modifié

je crois qu'exécuter une commande externe avec un environnement légèrement modifié est un cas très courant. C'est comme ça que j'ai tendance à le faire:

import subprocess, os
my_env = os.environ
my_env["PATH"] = "/usr/sbin:/sbin:" + my_env["PATH"]
subprocess.Popen(my_command, env=my_env)

j'ai le pressentiment qu'il y a une meilleure façon; est-il bien?

205
demandé sur tacaswell 2010-02-09 20:55:16

8 réponses

je pense que os.environ.copy() est mieux si vous n'avez pas l'intention de modifier l'os.environ pour le processus en cours:

import subprocess, os
my_env = os.environ.copy()
my_env["PATH"] = "/usr/sbin:/sbin:" + my_env["PATH"]
subprocess.Popen(my_command, env=my_env)
280
répondu Daniel Burke 2016-05-16 17:32:20

cela dépend de la question. Si c'est pour cloner et modifier l'environnement une solution pourrait être:

subprocess.Popen(my_command, env=dict(os.environ, PATH="path"))

mais cela dépend un peu du fait que les variables remplacées sont des identificateurs Python valides, ce qu'ils sont le plus souvent (à quelle fréquence trouvez-vous des noms de variables d'environnement qui ne sont pas alphanumériques+underscore ou des variables qui commencent par un nombre?).

sinon vous pourriez écrire quelque chose comme:

subprocess.Popen(my_command, env=dict(os.environ, 
                                      **{"Not valid python name":"value"}))

dans le cas très étrange (à quelle fréquence utilisez-vous des codes de contrôle ou des caractères non ascii dans les noms de variables d'environnement?) que les clés de l'environnement sont bytes vous ne pouvez même pas (sur python3) utiliser cette construction.

comme vous pouvez le voir les techniques (en particulier la première) utilisées ici avantages sur les clés de l'environnement est normalement valide identificateurs python, et également connu à l'avance (au moment du codage), la deuxième approche a des problèmes. Dans les cas où ce n'est pas le cas, vous devriez probablement chercher une autre approche .

47
répondu skyking 2017-05-23 11:47:26

vous pourriez utiliser my_env.get("PATH", '') au lieu de my_env["PATH"] dans le cas PATH en quelque sorte Non défini dans l'environnement d'origine, mais autre que cela il semble très bien.

23
répondu SilentGhost 2010-02-09 18:09:53

avec Python 3.5 vous pouvez le faire de cette façon:

import os
import subprocess

my_env = {**os.environ, 'PATH': '/usr/sbin:/sbin:' + os.environ['PATH']}

subprocess.Popen(my_command, env=my_env)

ici nous finissons avec une copie de os.environ et dépassés PATH valeur.

il a été rendu possible par PEP 448 (généralisations supplémentaires de déballage).

autre exemple. Si vous avez un environnement par défaut (i.e. os.environ ), et un dict avec lequel vous voulez modifier les valeurs par défaut, vous pouvez l'exprimer comme ceci:

my_env = {**os.environ, **dict_with_env_variables}
6
répondu skovorodkin 2016-05-24 15:30:59

pour définir temporairement une variable d'environnement sans devoir copier l'os.objet envrion etc, je fais ceci:

process = subprocess.Popen(['env', 'RSYNC_PASSWORD=foobar', 'rsync', \
'rsync://username@foobar.com::'], stdout=subprocess.PIPE)
3
répondu MFB 2016-09-07 06:16:14

le paramètre env accepte un dictionnaire. Vous pouvez simplement prendre os.environ, ajouter une clé (de votre choix variable) (une copie de la dict si vous devez) et l'utiliser comme un paramètre à Popen .

2
répondu Noufal Ibrahim 2010-02-09 18:13:28

je sais que cela a été répondu depuis un certain temps, mais il y a des points que certains peuvent vouloir connaître l'utilisation de PYTHONPATH au lieu de PATH dans leur variable d'environnement. J'ai décrit une explication de l'exécution de scripts python avec cronjobs qui traite l'environnement modifié d'une manière différente ( trouvé ici ). Pensé qu'il pourrait être bon pour ceux qui, comme moi, juste un peu plus de cette réponse.

1
répondu derigible 2017-05-23 12:03:02

dans certaines circonstances, vous pouvez ne transmettre que les variables d'environnement dont votre sous-processus a besoin, mais je pense que vous avez la bonne idée en général (c'est comme ça que je le fais aussi).

0
répondu Andrew Aylett 2010-02-09 18:08:43