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

Ore*_*n_H 255 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)
Run Code Online (Sandbox Code Playgroud)

我有一种直觉,觉得有更好的方法; 看起来好吗?

小智 366

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)
Run Code Online (Sandbox Code Playgroud)

  • @ user1338062:使用`os.environ.copy()`使其工作. (4认同)
  • @ user1338062您正在将实际方法`os.environ.copy`分配给`env`变量,但是您需要将调用方法`os.environ.copy()`的结果赋给`env`. (4认同)
  • 只有在`subprocess.Popen`调用中使用`shell = True`时,环境变量解析才有效.请注意,这样做可能会带来安全隐患. (4认同)

sky*_*ing 60

这取决于问题所在.如果要克隆和修改环境,一个解决方案可能是:

subprocess.Popen(my_command, env=dict(os.environ, PATH="path"))
Run Code Online (Sandbox Code Playgroud)

但这在某种程度上取决于被替换的变量是有效的python标识符,它们最常见的是(您多久会遇到不是字母数字+下划线的环境变量名称或以数字开头的变量?).

否则你可以写下这样的东西:

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

在非常奇怪的情况下(你经常在环境变量名中使用控制代码或非ascii字符吗?)环境的密钥是bytes你不能(在python3上)甚至使用那个结构.

正如您所看到的,这里使用的技术(特别是第一个)通常是有效的python标识符,并且事先已知(在编码时),第二种方法存在问题.如果情况并非如此,您应该寻找其他方法.

  • 给予好评.我不知道你可以写`dict(mapping,**kwargs)`.我以为是其中之一.注意:它复制`os.environ`而不修改它[@Daniel Burke在当前接受的答案中建议](http://stackoverflow.com/a/4453495/4279),但你的答案更简洁.在Python 3.5+中你甚至可以做`dict(**{'x':1},y = 2,**{'z':3})`.见[pep 448](https://www.python.org/dev/peps/pep-0448/). (3认同)

Sil*_*ost 23

您可以使用my_env.get("PATH", '')替代my_env["PATH"]的情况下,PATH莫名其妙地不是在原来的环境中定义,但比它看起来罚款等.


sko*_*kin 15

使用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)
Run Code Online (Sandbox Code Playgroud)

在这里,我们最终获得了一个os.environ被覆盖的PATH值的副本.

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

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

my_env = {**os.environ, **dict_with_env_variables}
Run Code Online (Sandbox Code Playgroud)


MFB*_*MFB 9

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

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


Nou*_*him 5

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