我能在Python中运行bash脚本并保留任何它导出的环境变量吗?

5
标题已经说明了一切。
假设我有一个bash脚本:
```bash ```
#!/bin/bash

# do some magic here, perhaps fetch something with wget, and then:
if [ "$VAR1" = "foo" ]; then
    export CASEVARA=1
fi
export CASEVARB=2

# and potentially many other vars...

我该如何从Python运行此脚本并检查设置了哪些环境变量。理想情况下,我希望将它们“反向继承”到正在运行Python的主环境中。
这样我就可以通过以下方式访问它们:
import os

# run the bash script somehow

print os.environ['CASEVARA']

1
不,变量导出仅适用于“子”shell。您无法继承到“祖先”shell中。 - Marc B
3个回答

8
当然可以!只需要进行一些技巧操作即可:

variables = subprocess.Popen(
    ["bash", "-c", "trap 'env' exit; source \"$1\" > /dev/null 2>&1",
       "_", "yourscript"],
    shell=False, stdout=subprocess.PIPE).communicate()[0]

这将运行您未修改的脚本,并以foo=bar的形式在不同的行上提供所有导出变量。

在支持的操作系统上(如GNU),您可以使用trap 'env -0' exit来获取分隔符为\0的变量,以支持多行值。


哇,这真的起作用了!我几乎不知道它是如何工作的,但它确实能工作:) 我的意思是,“trap”,“”_“”,什么? - frnhr
1
trap env exit 在 bash 退出时运行 envsource file; env 可以工作,但如果脚本使用 exit 将会失败)。第一个非选项参数(这里是 _)在脚本中成为 $0,它在很大程度上是任意的,所以我将其命名为 _,通常用于表示“不关心”。 - that other guy
1
谢谢。为了补充你的答案,这是我将它们解析到Python环境中的方法:os.environ.update(dict([line.split('=') for line in variables.split()])) - frnhr
2
@frnhr 不错。你可以使用 variables.split("\n") 来避免在变量中包含空格时出错,使用 line.split('=', 1) 来避免在变量中包含等号时出错,并过滤掉没有 = 的条目,因为这只是惯例而不一定是必需的。 - that other guy
它在Python2.7中工作吗?os.environ.update(dict([line.split('=') for line in variables.split()])) - Alex Brodov
非常有用;谢谢!在Python3中,为了对基本字符串进行操作,我需要解码原始字节串(variables.decode(sys.stdout.encoding))。 - orphen

2

使用子进程模块:

  • 在你的shell脚本中回显变量
  • 使用subprocess.Popen运行bash脚本,并设置stdout=subprocess.PIPE
  • 使用subprocess.communicate()获取结果
  • 保存到python变量中

0
为了让它对bash脚本透明,您可以从subprocess中子类化Popen,并让它公开其进程的环境。您也可以直接从磁盘上获取其环境的内容。
with open('/proc/%s/environ' % (pid,)) as f:
    env = f.read().replace('\x00', '\n')

这样做或许可行,但你会在进程关闭和清理的竞争中挣扎。


而且...那个人的建议好多了 :) - aychedee

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