web-dev-qa-db-ja.com

環境変数をpythonで設定できないのはなぜですか?

pythonスクリプトを作成して、シミュレーションコードを実行するディレクトリでスクリプトを実行することにより、適切な環境変数を作成することを望んでいました。これらのenv変数をmac osターミナルに保持するためのスクリプトです。

これは本当ですか?

そして

それは役に立つことだと思われます。なぜ一般にできないのですか?

40
physicsmichael

あなたはPythonからそれを行うことはできませんが、いくつかの巧妙なbashトリックは同様のことをすることができます。基本的な理由は次のとおりです。環境変数はプロセスごとのメモリ空間に存在します。 fork()で新しいプロセスが作成されると、そのプロセスは親の環境変数を継承します。次のようにシェルで環境変数(bashなど)を設定すると:

export VAR="foo"

あなたがしているのは、プロセス空間の変数VARを「foo」に設定するようにbashに指示することです。プログラムを実行すると、bashはfork()を使用してからexec()を使用してプログラムを実行するため、bashから実行するものはすべてbash環境変数を継承します。

ここで、現在のディレクトリにある「.data」というファイルのコンテンツを使用して環境変数DATAを設定するbashコマンドを作成するとします。まず、ファイルからデータを取得するコマンドが必要です。

cat .data

それはデータを印刷します。次に、bashコマンドを作成して、そのデータを環境変数に設定します。

export DATA=`cat .data`

このコマンドは、.dataの内容を取得し、環境変数DATAに入れます。これで、エイリアスコマンド内にそれを配置すると、環境変数を設定するbashコマンドができます。

alias set-data="export DATA=`cat .data`"

そのエイリアスコマンドをホームディレクトリの.bashrcまたは.bash_profileファイル内に配置して、起動した新しいbashシェルでそのコマンドを使用できるようにすることができます。

32
Benson

回避策の1つは、exportコマンドを出力し、親シェルにこれを評価させることです。

thescript.py

import pipes
import random
r = random.randint(1,100)
print("export BLAHBLAH=%s" % (pipes.quote(str(r))))

..およびbashエイリアス(ほとんどのシェルで同じことができます。tcshでさえも!):

alias setblahblahenv="eval $(python thescript.py)"

使用法:

$ echo $BLAHBLAH

$ setblahblahenv
$ echo $BLAHBLAH
72

次のような複数のコマンドを含む、任意のシェルコードを出力できます。

export BLAHBLAH=23 SECONDENVVAR='something else' && echo 'everything worked'

動的に作成された出力(pipes.quoteモジュールはこれに適しています)

20
dbr

pythonスクリプト(または他のスクリプトまたはプログラム)内で環境変数を設定しても、親シェルには影響しません。

説明を編集:あなたの質問への答えはイエスです、それは本当です。ただし、シェルスクリプト内からエクスポートし、ドット呼び出しを使用してソースを作成できます。

fooexport.shで

export FOO="bar"

コマンドプロンプトで

$ . ./fooexport.sh
$ echo $FOO
bar
3
Stefano Borini

私がやりたいのは、シェルスクリプトで/ usr/bin/envを使用して、同様の状況にいるときにコマンドラインを「ラップ」することです。

#!/bin/bash

/usr/bin/env NAME1="VALUE1" NAME2="VALUE2" ${*}

このスクリプトを「myappenv」と呼びましょう。 $ PATHにある$ HOME/binディレクトリに配置します。

これで、「myappenv」を次のように追加するだけで、その環境を使用してコマンドを呼び出すことができます。

myappenv dosometask -xyz

他の投稿されたソリューションも動作しますが、これは私の個人的な好みです。 1つの利点は、環境が一時的であるため、シェルで作業している場合、呼び出すコマンドのみが変更された環境の影響を受けることです。

新しいコメントに基づいて修正されたバージョン

#!/bin/bash

/usr/bin/env G4WORKDIR=$PWD ${*}

これもすべてエイリアスでラップできます。他の環境も準備する傾向があるので、ラッパースクリプトアプローチを好みます。これにより、メンテナンスが容易になります。

2
Joe Holloway

一般的には不可能です。 pythonのために作成された新しいプロセスは、その親プロセスの環境に影響を与えることはできません。親も子に影響を与えることはできません。

おそらく、MacOSの.bashrc.profileまたは同等の「ログイン時に実行」または「すべての新しいターミナルセッションで実行」スクリプトで設定できます。

python希望する環境でシミュレーションプログラムを開始することもできます。subprocess.Popenにenvパラメーターを使用してください( http://docs.python。 org/library/subprocess.html ))

import subprocess, os
os.chdir('/home/you/desired/directory')
subprocess.Popen(['desired_program_cmd', 'args', ...], env=dict(SOMEVAR='a_value') )

または、python .sh拡張子を持つファイルにこのようなシェルスクリプトを書き出すことができます:

export SOMEVAR=a_value
cd /home/you/desired/directory
./desired_program_cmd

そしてchmod +xそれをどこからでも実行します。

1
Joe Koberg

Bensonが回答したとおりですが、最善のハックアラウンドは、引数を保持するための単純なbash関数を作成することです。

upsert-env-var (){ eval $(python upsert_env_var.py $*); }

引数を指定してpythonスクリプトで何でもできます。変数を追加するには、次のようなものを使用します。

var = sys.argv[1]
val = sys.argv[2]
if os.environ.get(var, None):
    print "export %s=%s:%s" % (var, val, os.environ[var])
else:
    print "export %s=%s" % (var, val)

使用法:

upsert-env-var VAR VAL
0
Niall