シミュレーションコードを実行するディレクトリでスクリプトを実行することにより、適切な環境変数を作成するためのPythonスクリプトを作成したいと思っていましたが、これらの環境変数を永続化するスクリプトを作成できないことを読みましたマックOS端末。だから2つのこと:
これは本当ですか?
と
便利なことのようです。なぜ一般にはできないのですか?
シミュレーションコードを実行するディレクトリでスクリプトを実行することにより、適切な環境変数を作成するためのPythonスクリプトを作成したいと思っていましたが、これらの環境変数を永続化するスクリプトを作成できないことを読みましたマックOS端末。だから2つのこと:
これは本当ですか?
と
便利なことのようです。なぜ一般にはできないのですか?
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 シェルでそのコマンドを使用できるようにすることができます。
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
モジュールはこれに適しています)。
Python スクリプト (またはその他のスクリプトやプログラム) 内で環境変数を設定しても、親シェルには影響しません。
明確化を編集:あなたの質問に対する答えはイエスです、それは本当です。ただし、シェルスクリプト内からエクスポートし、ドット呼び出しを使用してそれをソースすることができます
fooexport.sh で
export FOO="bar"
コマンドプロンプトで
$ . ./fooexport.sh
$ echo $FOO
bar
一般的にはありえません。Python 用に作成された新しいプロセスは、その親プロセスの環境に影響を与えることはできません。親も子に影響を与えることはできませんが、親は新しいプロセス作成の一部として子の環境をセットアップできます。
おそらく、それらを.bashrc
、.profile
または同等の「ログイン時に実行」またはMacOSの「新しいターミナルセッションごとに実行」スクリプトで設定できます。
必要な環境でシミュレーション プログラムを python で開始することもできます。(env
パラメーターを使用して subprocess.Popen ( 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') )
.sh
または、Python で次のようなシェル スクリプトを拡張子付きのファイルに書き出すこともできます。
export SOMEVAR=a_value
cd /home/you/desired/directory
./desired_program_cmd
そしてそれchmod +x
をどこからでも実行します。
私が好きなのは、シェルスクリプトで /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 ${*}
これをエイリアスにまとめることもできます。私はラッパー スクリプト アプローチを好みます。これは、他の環境の準備も行う傾向があるためです。これにより、保守が容易になります。
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