web-dev-qa-db-ja.com

Pythonサブプロセス/環境を変更したPopen

環境を少し変更して外部コマンドを実行するのは非常に一般的なケースだと思います。それは私がそれをする傾向がある方法です:

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

もっと良い方法があると感じています。それは大丈夫に見えますか?

239
Oren_H

現在のプロセスの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)
334
Daniel Burke

それは問題が何であるかに依存します。環境を複製して変更する場合、1つのソリューションは次のようになります。

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

しかし、それは置き換えられた変数が有効なpython識別子であることに多少依存します。これらはほとんどの場合(英数字+アンダースコアまたは数字で始まる変数ではない環境変数名に遭遇する頻度は?) 。

それ以外の場合は、次のように記述できます。

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

環境のキーがbytesであるという非常に奇妙なケース(どのくらいの頻度で環境変数名に制御コードまたは非ASCII文字を使用しますか?)では、その構成を使用することさえできません(python3で)。

ここで使用される手法(特に最初の手法)が環境のキーに与える利点を見るとわかるように、通常は有効なpython識別子であり、事前に(コーディング時に)知られているため、2番目のアプローチには問題があります。そうでない場合は、おそらく 別のアプローチ を探す必要があります。

55
skyking

元の環境でPATHが何らかの形で定義されていない場合にmy_env["PATH"]の代わりにmy_env.get("PATH", '')を使用できますが、それ以外は問題ありません。

23
SilentGhost

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 (Additional Unpacking Generalizations)によって可能になりました。

もう一つの例。デフォルトの環境(つまりos.environ)があり、デフォルトをオーバーライドする辞書がある場合、次のように表現できます。

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

Os.environオブジェクトなどをコピーせずに一時的に環境変数を設定するには、次のようにします。

process = subprocess.Popen(['env', 'RSYNC_PASSWORD=foobar', 'rsync', \
'rsync://[email protected]::'], stdout=subprocess.PIPE)
8
MFB

Envパラメーターは辞書を受け入れます。 os.environを取得し、そのキー(必要な変数)を(必要に応じてdictのコピーに)追加し、Popenのパラメーターとして使用できます。

2
Noufal Ibrahim

これは以前から回答されてきましたが、環境変数でPATHの代わりにPYTHONPATHを使用することについて知りたい点がいくつかあります。変更された環境を別の方法で処理するcronジョブでpythonスクリプトを実行する説明の概要を示しました( found here )。私のように、この答えが提供する以上のことを必要としている人たちにとっては良いことだと思った。

1
derigible

特定の状況では、サブプロセスに必要な環境変数のみを渡したいと思うかもしれませんが、一般的には正しい考えを持っていると思います(私もそうしています)。

0
Andrew Aylett