在Python脚本中设置环境变量

103

我有一个Bash脚本,它设置了一个环境变量并运行一个命令。

LD_LIBRARY_PATH=my_path
sqsub -np $1 /homedir/anotherdir/executable

现在我想使用Python替代Bash,因为我想计算一些传递给命令的参数。

我已经尝试过

putenv("LD_LIBRARY_PATH", "my_path")

call("export LD_LIBRARY_PATH=my_path")

后跟着

call("sqsub -np " + var1 + "/homedir/anotherdir/executable")

但程序总是放弃,因为没有设置LD_LIBRARY_PATH。

我该如何解决这个问题?

感谢您的帮助!

(如果我在调用Python脚本之前导出LD_LIBRARY_PATH,一切都正常,但我希望Python确定路径并将环境变量设置为正确的值)


1
可能是更改当前进程环境的重复问题。 - S.Lott
2
@S.Lott:您能否请解释一下我如何将那个线程应用到我的问题上?(因为我不太理解它) - Matthias 009
@S.Lott(补充):特别是该线程中被接受的答案以“os.environ [“LD_LIBRARY_PATH”]不起作用的原因”开头,在我的情况下它起作用。 - Matthias 009
3个回答

109

bash:

LD_LIBRARY_PATH=my_path
sqsub -np $1 /path/to/executable

在Python中类似的:

import os
import subprocess
import sys

os.environ['LD_LIBRARY_PATH'] = "my_path" # visible in this process + all children
subprocess.check_call(['sqsub', '-np', sys.argv[1], '/path/to/executable'],
                      env=dict(os.environ, SQSUB_VAR="visible in this subprocess"))

subprocess.check_call(command, env=os.environ) 'module' object has no attribute 'check_call',我现在尝试使用call。 - Matthias 009
我会避免这样的解决方案,因为它会改变当前进程环境。最好将其副本传递给子进程。 - rdesgroppes
2
在这个编程过程中,解释非常重要:可见性和所有子元素。 - debuti
2
@rdesgroppes:我添加了一个选项(env),其中更新的环境仅在子进程中可见($SQSUB_VAR在当前进程的环境中保持不变)。 - jfs
这个能同样适用于“HOME”路径吗? - alper

22

你可以使用以下方法向你的环境中添加元素:

os.environ['LD_LIBRARY_PATH'] = 'my_path'

通过使用shell(使用您的os.environ)运行子进程,可以使用以下方法:

subprocess.call('sqsub -np ' + var1 + '/homedir/anotherdir/executable', shell=True)

21

这里有很多好的答案,但您应该尽可能避免使用 shell=True 来传递不可信的变量,因为这是一种安全风险。这些变量可能会溢出到shell并运行任意命令!如果你确实无法避免,至少请使用Python3的shlex.quote()来转义字符串(如果有多个以空格分隔的参数,请引用每个拆分而不是整个字符串)。

当您传递参数数组时,shell=False始终是默认值。

现在是安全的解决方案...

方法#1

更改自己的进程环境 - 新环境将应用于python本身和所有子进程。

os.environ['LD_LIBRARY_PATH'] = 'my_path'
command = ['sqsub', '-np', var1, '/homedir/anotherdir/executable']
subprocess.check_call(command)

方法 #2

复制环境并将其传递给子进程。您可以完全控制子进程的环境,而不会影响Python自身的环境。

myenv = os.environ.copy()
myenv['LD_LIBRARY_PATH'] = 'my_path'
command = ['sqsub', '-np', var1, '/homedir/anotherdir/executable']
subprocess.check_call(command, env=myenv)

第三种方法

仅适用于Unix系统:执行env以设置环境变量。如果你有多个变量要修改,这种方法会更加繁琐并且不太便携,但是和方法二一样,你可以完全控制Python和子环境。

command = ['env', 'LD_LIBRARY_PATH=my_path', 'sqsub', '-np', var1, '/homedir/anotherdir/executable']
subprocess.check_call(command)
当然,如果var1包含多个以空格分隔的参数,它们现在将作为带有空格的单个参数传递。要保留shell=True的原始行为,您必须构建一个包含拆分字符串的命令数组:
command = ['sqsub', '-np'] + var1.split() + ['/homedir/anotherdir/executable']

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接