从Python脚本中导入Bash变量

3

我看过许多从bash脚本中运行python脚本的实例,要么将变量作为参数传递,要么使用export让子shell访问变量。但是我在这里尝试做相反的事情。

我正在运行一个python脚本,并有一个单独的文件,我们将其称为myGlobalVariables.bash

myGlobalVariables.bash:

foo_1="var1"    
foo_2="var2"   
foo_3="var3"  

我的Python脚本需要使用这些变量。
举个简单的例子:

myPythonScript.py:

print "foo_1: {}".format(foo_1)

有没有直接导入它们的方法?另外,如果可能的话,我不想修改bash脚本,因为这是一个经常在其他地方引用的共同文件。


你的意思是想从Python解析Bash文件吗?这不会很容易。你的脚本除了变量声明之外还包含命令吗? - Jean-François Fabre
它确实可以,但并不多。我本来想避免解析,但如果那是唯一的选择,我肯定可以做到。 - Bagelstein
你想引用的变量都是简单赋值吗?例如 var_name=var_val - 这样就没有 shell 扩展、命令替换等。 - theorifice
4个回答

3
如果您的.bash文件格式如您所述 - 您可以通过imp模块直接将其作为Python模块导入。
import imp
bash_module = imp.load_source("bash_module, "/path/to/myGlobalVariables.bash")
print bash_module.foo_1

"imp.load_source(name, pathname[, file]) 加载并初始化作为Python源文件实现的模块,并返回其模块对象。" 没有提到bash... - Jean-François Fabre
根据 OP 对 myGlobalVariables.bash 的描述 - 它可能被解释为 Python 文件。 - theorifice
1
不错的黑客技巧。可能会奏效……一个“导出”就可以让你消失 :) - Jean-François Fabre
嗯,我尝试了这个,出现了以下错误: SyntaxError:扫描字符串文字时的EOL我认为这与格式错误有关。 格式并不像我在示例中所示那样简单,有几行不遵循该格式。 - Bagelstein
在这种情况下,您只需要解析内容。假设所有变量分配都很简单,您可能只需使用正则表达式。 - theorifice
看起来这是Python2的示例。我收到了DeprecationWarning:imp模块已被弃用,应使用importlib;请参阅该模块的文档以获取替代用途。 - Ashark

1
您也可以使用os.environ:
Bash:
#!/bin/bash
# works without export as well
export testtest=one

Python:

#!/usr/bin/python
import os
os.environ['testtest']  # 'one'

在这种情况下,你需要以某种方式从Python中执行.bash文件 - 或者在Python代码运行之前执行它。 - theorifice
在Python中执行不起作用。而且,在此之前,OP似乎说这很容易。确实如此。 - Jean-François Fabre
@theorifice 我认为这个问题意味着在设置了这些变量之后,从bash文件中调用Python脚本。 - Marat

0

我对Python非常陌生,因此欢迎提出更惯用的方法。以下代码使用bash本身告诉我们哪些值被设置,首先通过调用一个空环境的bash(env -i bash)来确定基线中设置了哪些变量,然后再次调用它并告诉bash来源化您的“variables”文件,最后告诉我们现在设置了哪些变量。
删除一些误报和明显为空的行之后,我遍历“additional”输出,查找不在基线中的变量。新看到的变量被拆分(小心翼翼)并放入bash字典中。
我保留了以前使用exec在Python中本地设置变量的想法(但注释掉了),但我遇到了引号/转义问题,所以我改变了思路,使用了字典。

如果您的“variables”文件的确切调用(路径等)与我的不同,则需要更改该值的所有实例-在subprocess.check_output()调用中,在list.remove()调用中。

这是我使用的示例变量文件,只是为了演示可能发生的一些事情:
foo_1="var1"
foo_2="var2"
foo_3="var3"
if [[ -z $foo_3 ]]; then
    foo_4="test"
else
    foo_4="testing"
fi
foo_5="O'Neil"
foo_6='I love" quotes'
foo_7="embedded
newline"

...这是Python脚本:

#!/usr/bin/env python

import subprocess

output = subprocess.check_output(['env', '-i', 'bash', '-c', 'set'])
baseline = output.split("\n")

output = subprocess.check_output(['env', '-i', 'bash', '-c', '. myGlobalVariables.bash; set'])
additional = output.split("\n")

# these get set when ". myGlobal..." runs and so are false positives
additional.remove("BASH_EXECUTION_STRING='. myGlobalVariables.bash; set'")
additional.remove('PIPESTATUS=([0]="0")')
additional.remove('_=myGlobalVariables.bash')
# I get an empty item at the end (blank line from subprocess?)
additional.remove('')

bash = {}
for assign in additional:
        if not assign in baseline:
                name, value = assign.split("=", 1)
                bash[name]=value
                #exec(name + '="' + value + '"')

print "New values:"
for key in bash:
  print "Key: ", key, " = ", bash[key]

另一种方法:

Marat的答案的启发下,我想出了这个两阶段的黑客。先用一个Python程序开始,让我们称之为“第一阶段”,它使用subprocess调用bash来源文件变量,就像我上面的答案一样,但是然后告诉bash导出所有变量,然后执行你Python程序的其余部分,也就是“第二阶段”。

第一阶段Python程序:

#!/usr/bin/env python

import subprocess

status = subprocess.call(
  ['bash', '-c',
  '. myGlobalVariables.bash; export $(compgen -v); exec ./stage2.py'
  ]);

第二阶段的Python程序:

#!/usr/bin/env python
# anything you want! for example,
import os
for key in os.environ:
  print key, " = ", os.environ[key]

0

жӯЈеҰӮ@theorificeзҡ„еӣһзӯ”жүҖиҝ°пјҢиҝҷйҮҢзҡ„иҜҖзӘҚеҸҜиғҪжҳҜиҝҷж ·ж јејҸеҢ–зҡ„ж–Ү件еҸҜд»Ҙиў«и§ЈйҮҠдёәbashе’Ңpythonд»Јз ҒгҖӮдҪҶд»–зҡ„еӣһзӯ”е·Із»ҸиҝҮж—¶дәҶгҖӮimpжЁЎеқ—е·Іиў«ејғз”ЁпјҢеҸ–иҖҢд»Јд№Ӣзҡ„жҳҜimportlibгҖӮ

з”ұдәҺжӮЁзҡ„ж–Ү件жү©еұ•еҗҚдёҚжҳҜвҖң.pyвҖқпјҢеӣ жӯӨжӮЁеҸҜд»ҘдҪҝз”Ёд»ҘдёӢж–№жі•пјҡ

from importlib.util import spec_from_loader, module_from_spec
from importlib.machinery import SourceFileLoader 

spec = spec_from_loader("foobar", SourceFileLoader("foobar", "myGlobalVariables.bash"))
foobar = module_from_spec(spec)
spec.loader.exec_module(foobar)

我并不完全理解这段代码是如何工作的(尤其是那些 foobar 参数),但它对我来说是有效的。在这里找到了它。


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