繁体   English   中英

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

[英]Python subprocess/Popen with a modified environment

我相信在稍微修改环境的情况下运行外部命令是一种非常常见的情况。 这就是我倾向于这样做的方式:

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,我认为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)

这取决于问题是什么。 如果要克隆和修改环境,一种解决方案可能是:

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 标识符,并且也提前知道(在编码时),第二种方法有问题。 在情况并非如此的情况下,您可能应该寻找另一种方法

使用 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 ),以及一个你想覆盖默认值的字典,你可以这样表达:

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

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

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

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

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

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

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

暂无
暂无

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

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