为什么python中设置的环境变量不能持久存在?

时间:2009-04-03 22:55:30

标签: python persistence environment-variables

我希望通过在我将执行某些模拟代码的任何目录中运行脚本来编写一个python脚本来创建一些适当的环境变量,并且我已经读过我无法编写脚本来制作这些环境变量vars在mac os终端中持续存在。所以有两件事:

这是真的吗?

这似乎是一件有用的事情;一般来说为什么不可能?

8 个答案:

答案 0 :(得分:32)

你无法从python中做到这一点,但是一些聪明的bash技巧可以做类似的事情。基本原因是:环境变量存在于每进程内存空间中。使用fork()创建新进程时,它继承其父级的环境变量。在shell中设置环境变量(例如bash)时,如下所示:

export VAR="foo"

你正在做的是告诉bash将其进程空间中的变量VAR设置为“foo”。当你运行一个程序时,bash使用fork()然后使用exec()来运行程序,所以从bash运行的任何东西都会继承bash环境变量。

现在,假设您要创建一个bash命令,该命令使用当前目录中名为“.data”的文件中的内容设置一些环境变量DATA。首先,您需要有一个命令来从文件中获取数据:

cat .data

打印数据。现在,我们要创建一个bash命令来在环境变量中设置该数据:

export DATA=`cat .data`

该命令获取.data的内容并将其放入环境变量DATA中。现在,如果你把它放在别名命令中,你有一个bash命令来设置你的环境变量:

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

您可以将alias命令放在主目录中的.bashrc或.bash_profile文件中,以便在您启动的任何新bash shell中使用该命令。

答案 1 :(得分:19)

一种解决方法是输出export命令,并让父shell评估此..

thescript.py

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

..和bash别名(在大多数shell中也可以这样做..甚至tcsh!):

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

用法:

$ echo $BLAHBLAH

$ setblahblahenv
$ echo $BLAHBLAH
72

您可以输出任意shell代码,包括多个命令,如:

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

请记住要小心转义任何动态创建的输出(pipes.quote模块对此有利)

答案 2 :(得分:3)

如果在python脚本(或任何其他脚本或程序)中设置环境变量,它将不会影响父shell。

编辑说明: 所以问题的答案是肯定的,这是事实。 但是,您可以从shell脚本中导出并使用点调用

来源它 在fooexport.sh

export FOO="bar"

在命令提示符下

$ . ./fooexport.sh
$ echo $FOO
bar

答案 3 :(得分:2)

我喜欢做的是在shell脚本中使用/ usr / bin / env在我发现自己处于类似情况时“包装”我的命令行:

#!/bin/bash

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

所以让我们称这个脚本为“myappenv”。我把它放在$ HOME / bin目录中,我在$ PATH中。

现在我可以通过简单地预先添加“myappenv”来调用使用该环境的任何命令:

myappenv dosometask -xyz

其他已发布的解决方案也有效,但这是我个人的偏好。一个优点是环境是暂时的,所以如果我在shell中工作,只有我调用的命令会受到改变的环境的影响。

基于新评论的修改版

#!/bin/bash

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

你也可以把它全部包装在一个别名中。我更喜欢包装脚本方法,因为我也倾向于在其中进行其他环境准备,这使我更容易维护。

答案 4 :(得分:1)

通常不可能。为python创建的新进程不会影响其父进程的环境。父母也不会影响孩子,但父母可以设置孩子的环境作为新流程创建的一部分。

也许您可以在.bashrc.profile或等效的“登录时运行”或“在每个新的终端会话上运行”脚本中设置它们。

您也可以让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') )

或者你可以让python将这样的shell脚本写到一个扩展名为.sh的文件中:

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

然后chmod +x它并从任何地方运行它。

答案 5 :(得分:0)

正如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

答案 6 :(得分:0)

正如其他人指出的那样,这种方法行不通的原因是环境变量存在于每个进程的内存空间中,并因此在Python进程退出时死亡。

他们指出,对此的一种解决方案是在.bashrc中定义一个别名来执行您想要的操作,例如:

alias export_my_program="export MY_VAR=`my_program`"

但是,还有另一种方法(一点点技巧)既不需要您修改.bachrc,也不需要您在my_program中包含$PATH(或指定其完整路径)在别名中)。想法是如果正常调用(./my_program),则在Python中运行该程序;如果源(source my_program),则在Bash中运行该程序。 (在脚本上使用source不会产生新进程,因此不会杀死其中创建的环境变量。)您可以按照以下步骤进行操作:

my_program.py

#!/usr/bin/env python3

_UNUSED_VAR=0
_UNUSED_VAR=0 \
<< _UNUSED_VAR
#=======================
# Bash code starts here
#=======================
'''
_UNUSED_VAR
export MY_VAR=`$(dirname $0)/my_program.py`
echo $MY_VAR
return
'''

#=========================
# Python code starts here
#=========================
print('Hello environment!')

在Python(./my_program.py)中运行此命令,前三行没有任何用处,并且三引号会注释掉Bash代码,从而使Python能够正常运行而不会受到Bash语法错误的影响。

heredoc(source my_program.py)以bash(<< _UNUSED_VAR)提供,这是一种用于“注释掉”三重引用的技巧,否则将是语法错误。该脚本在到达第二个三引号之前返回,避免了另一个语法错误。 export将在Python中运行my_program.py的结果从正确的目录(由$(dirname $0)给定)分配给环境变量MY_VARecho $MY_VAR在命令行上显示结果。

用法示例:

$ source my_program.py
Hello environment!
$ echo $MY_VAR
Hello environment!

但是,该脚本仍会执行它之前的所有操作,除了正常运行时会导出环境变量:

$ ./my_program.py
Hello environment!
$ echo $MY_VAR
                                <-- Empty line

答案 7 :(得分:0)

正如其他作者所指出的,当 Python 进程退出时,内存会被丢弃。但是在python过程中,可以编辑运行环境。例如:

>>> os.environ["foo"] = "bar"
>>> import subprocess
>>> subprocess.call(["printenv", "foo"])
bar
0
>>> os.environ["foo"] = "foo"
>>> subprocess.call(["printenv", "foo"])
foo
0