修改环境的 Python subprocess/Popen
- 2024-12-23 08:43:00
- admin 原创
- 80
问题描述:
我相信运行稍微修改环境的外部命令是一种非常常见的情况。我倾向于这样做:
import subprocess, os
my_env = os.environ
my_env["PATH"] = "/usr/sbin:/sbin:" + my_env["PATH"]
subprocess.Popen(my_command, env=my_env)
我有直觉认为有更好的方法;看起来还好吗?
解决方案 1:
我认为os.environ.copy()
如果您不打算修改当前进程的 os.environ 会更好:
import subprocess, os
my_env = os.environ.copy()
my_env["PATH"] = f"/usr/sbin:/sbin:{my_env['PATH']}"
subprocess.Popen(my_command, env=my_env)
解决方案 2:
这取决于问题是什么。如果要克隆和修改环境,一种解决方案可能是:
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 标识符,并且也是提前知道的(在编码时),第二种方法存在问题。如果不是这种情况,您可能应该寻找另一种方法。
解决方案 3:
使用 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}
解决方案 4:
您可能会使用my_env.get("PATH", '')
而不是以防my_env["PATH"]
在PATH
原始环境中未定义,但除此之外它看起来不错。
解决方案 5:
为了临时设置环境变量而不必复制 os.envrion 对象等,我执行以下操作:
process = subprocess.Popen(['env', 'RSYNC_PASSWORD=foobar', 'rsync', \n'rsync://username@foobar.com::'], stdout=subprocess.PIPE)
解决方案 6:
env 参数接受一个字典。您可以简单地获取 os.environ,向其中添加一个键(您想要的变量)(如果需要,可以添加到字典的副本中),并将其用作 的参数Popen
。
解决方案 7:
在较新版本的 Python 中,您可以使用函数env
的关键字参数,如下所示:run
import subprocess
import os
subprocess.run(["mycommand"], env=dict(os.environ) | {"FOO": "bar"})
因为我希望该进程继承现有的环境变量,所以我dict(os.environ)
使用联合运算符将其与我自己的覆盖环境变量字典合并,该运算符在 Python 3.9+ 中有效。
解决方案 8:
我知道这个问题已经回答了一段时间了,但是有些人可能想知道在他们的环境变量中使用 PYTHONPATH 而不是 PATH 的一些要点。我已经概述了使用 cronjobs 运行 python 脚本的解释,该脚本以不同的方式处理修改后的环境(在此处找到)。我认为这对那些像我一样需要比这个答案多一点的人会有所帮助。
解决方案 9:
在某些情况下,您可能只想传递子进程所需的环境变量,但我认为您总体上有一个正确的想法(我也是这样做的)。
解决方案 10:
这可能是一个解决方案:
new_env = dict([(k,(':'.join([env[k], v]) if k in env else v)) for k,v in os.environ.items()])
- 2024年20款好用的项目管理软件推荐,项目管理提效的20个工具和技巧
- 2024年开源项目管理软件有哪些?推荐5款好用的项目管理工具
- 2024年常用的项目管理软件有哪些?推荐这10款国内外好用的项目管理工具
- 项目管理软件有哪些?推荐7款超好用的项目管理工具
- 项目管理软件有哪些最好用?推荐6款好用的项目管理工具
- 项目管理软件哪个最好用?盘点推荐5款好用的项目管理工具
- 项目管理软件有哪些,盘点推荐国内外超好用的7款项目管理工具
- 项目管理软件排行榜:2024年项目经理必备5款开源项目管理软件汇总
- 2024项目管理软件排行榜(10类常用的项目管理工具全推荐)
- 项目管理必备:盘点2024年13款好用的项目管理软件