簡體   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