Вопрос

Я считаю, что запуск внешней команды со слегка измененной средой — очень распространенный случай.Вот как я обычно это делаю:

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

У меня есть нутром ощущение, что есть лучший способ;выглядит нормально?

Это было полезно?

Решение

Я думаю os.environ.copy() лучше, если вы не собираетесь изменять os.environ для текущего процесса:

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

Другие советы

Это зависит от того, в чем проблема.Если это клонирование и изменение среды, одним из решений может быть:

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

Но это в некоторой степени зависит от того, являются ли замененные переменные действительными идентификаторами Python, которыми они чаще всего и являются (как часто вы сталкиваетесь с именами переменных среды, которые не являются буквенно-цифровыми + подчеркивание или переменными, начинающимися с цифры?).

В противном случае вы можете написать что-то вроде:

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

В очень странном случае (как часто вы используете управляющие коды или символы, отличные от ASCII, в именах переменных среды?) ключи среды bytes вы не можете (на Python3) даже использовать эту конструкцию.

Как вы можете видеть, используемые здесь методы (особенно первый) имеют преимущества в отношении ключей среды, обычно это действительные идентификаторы Python, а также известные заранее (во время кодирования), второй подход имеет проблемы.В тех случаях, когда это не так, вам, вероятно, следует поискать другой подход.

ты можешь использовать my_env.get("PATH", '') вместо my_env["PATH"] в случае PATH почему-то не определено в исходной среде, но в остальном выглядит нормально.

В Python 3.5 вы можете сделать это следующим образом:

import os
import subprocess

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

subprocess.Popen(my_command, env=my_env)

Здесь мы получаем копию os.environ и переопределено PATH ценить.

Это стало возможным благодаря ПЭП 448 (Дополнительные обобщения распаковки).

Другой пример.Если у вас есть среда по умолчанию (т. os.environ), и словарь, с помощью которого вы хотите переопределить значения по умолчанию, вы можете выразить это следующим образом:

my_env = {**os.environ, **dict_with_env_variables}

Чтобы временно установить переменную среды без необходимости копировать объект os.envrion и т. д., я делаю это:

process = subprocess.Popen(['env', 'RSYNC_PASSWORD=foobar', 'rsync', \
'rsync://username@foobar.com::'], stdout=subprocess.PIPE)

Параметр env принимает словарь.Вы можете просто взять os.environ, добавить к нему ключ (нужную вам переменную) (в копию словаря, если необходимо) и использовать его в качестве параметра для Popen.

Я знаю, что на этот вопрос уже давно был дан ответ, но есть некоторые моменты, которые некоторые могут захотеть узнать об использовании PYTHONPATH вместо PATH в своей переменной среды.Я изложил объяснение запуска скриптов Python с помощью cronjobs, которое по-другому работает с измененной средой (нашел здесь).Думаю, это будет полезно для тех, кому, как и мне, нужно немного больше, чем дал этот ответ.

В определенных обстоятельствах вы можете захотеть передать только те переменные среды, которые нужны вашему подпроцессу, но я думаю, что в целом у вас есть правильная идея (я тоже так делаю).

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top