【问题标题】:set environment variable in python script在python脚本中设置环境变量
【发布时间】:2012-01-12 00:25:17
【问题描述】:

我有一个设置环境变量并运行命令的 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 确定路径并将环境变量设置为正确的值)

【问题讨论】:

  • @S.Lott:您能解释一下如何将该线程应用于我的问题吗? (因为我不明白)
  • @S.Lott (addentum):特别是该线程中的例外答案以“os.environ["LD_LIBRARY_PATH"] 不起作用的原因”开头,在我的情况下它有效

标签: python export


【解决方案1】:

重击:

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' 对象没有属性 'check_call',我现在尝试使用 call
  • 我会避免这样的解决方案,因为它会改变当前的流程环境。最好将它的副本传递给子进程。
  • 这里的解释很关键:在这个过程中可见+所有孩子
【解决方案2】:

您可以通过使用将元素添加到您的环境中

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

并通过使用在 shell(使用您的 os.environ)中运行子进程

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

【讨论】:

    【解决方案3】:

    这里有很多很好的答案,但您应该不惜一切代价避免使用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)
    

    方法#3

    仅限Unix:执行env 设置环境变量。如果您有许多变量要修改而不是 portabe,则更麻烦,但像 #2 一样,您保留对 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']
    

    【讨论】:

      【解决方案4】:

      紧凑的解决方案(前提是您不需要其他环境变量):

      call('sqsub -np {} /homedir/anotherdir/executable'.format(var1).split(),
            env=dict(LD_LIBRARY_PATH=my_path))
      

      使用 env 命令行工具:

      call('env LD_LIBRARY_PATH=my_path sqsub -np {} /homedir/anotherdir/executable'.format(var1).split())
      

      【讨论】:

      • 第一个命令不起作用(你应该在这里传递一个列表,而不是字符串和错误的环境(找不到sqsub))。如果var1 包含诸如'$`! 之类的shell 元字符,则第二个命令可能会中断。如果您不需要 shell=True,则使用它是一种不好的做法,例如,如果 var1 来自外部源,则可以进行命令注入。
      • @J.F.Sebastian 感谢您提出的非常有效的观点。我以某种方式称呼他们。当然,如果路径中有空格,拆分将不起作用。
      • 我的评论说没有关于分裂。这不是解决您的答案的合适方法:它不能解决 PATH 问题。它引入了其他问题。 My answer shows how to pass the list correctly.
      • @J.F.Sebastian 对,你的评论没有提到分裂……那又怎样?我的也是这样,有什么问题吗?也就是说,紧凑型和基于环境的解决方案都可以工作。试一试:他们解决了传递 LD_LIBRARY_PATH 的需求。
      猜你喜欢
      • 2020-04-05
      • 2012-01-19
      • 2016-12-23
      • 1970-01-01
      • 2013-11-15
      • 1970-01-01
      • 2014-01-29
      • 2016-10-07
      相关资源
      最近更新 更多