具有修改环境的Python子进程/ Popen

时间:2010-02-09 17:55:17

标签: python subprocess popen

我认为运行带有轻微修改环境的外部命令是一种非常常见的情况。这就是我倾向于这样做的方式:

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

我有一种直觉,认为有更好的方法;它看起来不错吗?

8 个答案:

答案 0 :(得分:332)

如果您不打算修改当前进程的os.environ,我认为os.environ.copy()更好:

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

答案 1 :(得分:55)

这取决于问题所在。如果要克隆和修改环境,可以采用以下解决方案:

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标识符,并且事先已知(在编码时),第二种方法存在问题。如果情况并非如此,您应该寻找another approach

答案 2 :(得分:23)

您可以使用my_env.get("PATH", '')代替my_env["PATH"],以防{id}}在原始环境中以某种方式未定义,但除此之外它看起来不错。

答案 3 :(得分:13)

使用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值的副本。

通过PEP 448(附加拆包概括)使其成为可能。

另一个例子。如果你有一个默认环境(即os.environ),并且想要覆盖默认值的dict,你可以这样表达:

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

答案 4 :(得分:8)

要临时设置环境变量而不必复制os.envrion对象等,我这样做:

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

答案 5 :(得分:2)

env参数接受字典。您可以简单地使用os.environ,添加一个键(您想要的变量)(如果必须,添加到dict的副本)并将其用作Popen的参数。

答案 6 :(得分:1)

我知道这已经回答了一段时间,但有些人可能想知道在环境变量中使用PYTHONPATH而不是PATH。我概述了使用cronjobs运行python脚本的解释,它以不同的方式处理修改后的环境(found here)。认为对于那些和我一样需要比提供的答案更多的人来说会有一些好处。

答案 7 :(得分:0)

在某些情况下,您可能只希望传递子进程所需的环境变量,但我认为您一般都有正确的想法(我也是如此)。