简体   繁体   English

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

[英]Python subprocess/Popen with a modified environment

I believe that running an external command with a slightly modified environment is a very common case.我相信在稍微修改环境的情况下运行外部命令是一种非常常见的情况。 That's how I tend to do it:这就是我倾向于这样做的方式:

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

I've got a gut feeling that there's a better way;我有一种直觉,有更好的方法; does it look alright?看起来好吗?

I think os.environ.copy() is better if you don't intend to modify the os.environ for the current process:如果您不打算修改当前进程的 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)

That depends on what the issue is.这取决于问题是什么。 If it's to clone and modify the environment one solution could be:如果要克隆和修改环境,一种解决方案可能是:

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

But that somewhat depends on that the replaced variables are valid python identifiers, which they most often are (how often do you run into environment variable names that are not alphanumeric+underscore or variables that starts with a number?).但这在某种程度上取决于被替换的变量是有效的 Python 标识符,它们最常见的是(您遇到不是字母数字+下划线的环境变量名称或以数字开头的变量的频率?)。

Otherwise you'll could write something like:否则,您可以编写如下内容:

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

In the very odd case (how often do you use control codes or non-ascii characters in environment variable names?) that the keys of the environment are bytes you can't (on python3) even use that construct.在非常奇怪的情况下(您在环境变量名称中使用控制代码或非 ascii 字符的频率如何?)环境的键是bytes您甚至不能(在 python3 上)使用该构造。

As you can see the techniques (especially the first) used here benefits on the keys of the environment normally is valid python identifiers, and also known in advance (at coding time), the second approach has issues.正如您所看到的,这里使用的技术(尤其是第一种)对环境密钥的好处通常是有效的 Python 标识符,并且也提前知道(在编码时),第二种方法有问题。 In cases where that isn't the case you should probably look for another approach .在情况并非如此的情况下,您可能应该寻找另一种方法

With Python 3.5 you could do it this way:使用 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)

Here we end up with a copy of os.environ and overridden PATH value.在这里,我们最终得到了os.environ的副本并覆盖了PATH值。

It was made possible by PEP 448 (Additional Unpacking Generalizations). PEP 448 (附加解包概括)使之成为可能。

Another example.另一个例子。 If you have a default environment (ie os.environ ), and a dict you want to override defaults with, you can express it like this:如果你有一个默认环境(即os.environ ),以及一个你想覆盖默认值的字典,你可以这样表达:

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

您可以使用my_env.get("PATH", '')而不是my_env["PATH"]以防PATH以某种方式未在原始环境中定义,但my_env["PATH"]它看起来不错。

To temporarily set an environment variable without having to copy the os.envrion object etc, I do this:要临时设置环境变量而不必复制 os.envrion 对象等,我这样做:

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

The env parameter accepts a dictionary. env 参数接受字典。 You can simply take os.environ, add a key (your desired variable) (to a copy of the dict if you must) to that and use it as a parameter to Popen .您可以简单地使用 os.environ,向其添加一个键(您想要的变量)(如果必须,添加到 dict 的副本)并将其用作Popen的参数。

I know this has been answered for some time, but there are some points that some may want to know about using PYTHONPATH instead of PATH in their environment variable.我知道这已经有一段时间了,但是有些人可能想知道在他们的环境变量中使用 PYTHONPATH 而不是 PATH 的一些要点。 I have outlined an explanation of running python scripts with cronjobs that deals with the modified environment in a different way ( found here ).我已经概述了使用 cronjobs 运行 python 脚本的解释,这些脚本以不同的方式处理修改后的环境( 在这里找到)。 Thought it would be of some good for those who, like me, needed just a bit more than this answer provided.认为这对那些像我一样需要比这个答案提供的更多的人有好处。

在某些情况下,您可能只想传递子流程所需的环境变量,但我认为您总体上有正确的想法(我也是这样做的)。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM