简体   繁体   English

从 python 脚本导入 bash 变量

[英]Import bash variables from a python script

I have seen plenty examples of running a python script from inside a bash script and either passing in variables as arguments or using export to give the child shell access, I am trying to do the opposite here though.我已经看到很多从 bash 脚本内部运行 python 脚本的例子,或者将变量作为参数传递或使用导出来授予子 shell 访问权限,但我在这里尝试做相反的事情。

I am running a python script and have a separate file, lets call it myGlobalVariables.bash我正在运行一个 python 脚本并有一个单独的文件,我们称之为 myGlobalVariables.bash

myGlobalVariables.bash: myGlobalVariables.bash:

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

My python script needs to use these variables.我的 python 脚本需要使用这些变量。

For a very simple example:举一个非常简单的例子:

myPythonScript.py:我的PythonScript.py:

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

Is there a way I can import them directly?有没有办法直接导入它们? Also, I do not want to alter the bash script if possible since it is a common file referenced many times elsewhere.另外,如果可能的话,我不想更改 bash 脚本,因为它是一个在其他地方多次引用的公共文件。

If your .bash file is formatted as you indicated - you might be able to just import it direct as a Python module via the imp module.如果您的.bash文件按照您的指示格式化 - 您可以通过imp模块将其直接作为 Python 模块imp

import imp
bash_module = imp.load_source("bash_module, "/path/to/myGlobalVariables.bash")
print bash_module.foo_1

You can also use os.environ:您还可以使用 os.environ:

Bash:重击:

#!/bin/bash
# works without export as well
export testtest=one

Python:蟒蛇:

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

I am very new to python, so I would welcome suggestions for more idiomatic ways to do this, but the following code uses bash itself to tell us which values get set by first calling bash with an empty environment ( env -i bash ) to tell us what variables are set as a baseline, then I call it again and tell bash to source your "variables" file, and then tell us what variables are now set.我对 python陌生,所以我欢迎提供更多惯用方法的建议,但是下面的代码使用 bash 本身告诉我们通过首先在空环境( env -i bash )中调用 bash 来告诉我们设置了哪些值我们将哪些变量设置为基线,然后我再次调用它并告诉 bash 获取您的“变量”文件,然后告诉我们现在设置了哪些变量。 After removing some false-positives and an apparently-blank line, I loop through the "additional" output, looking for variables that were not in the baseline.删除一些误报和明显的空白行后,我遍历“附加”输出,寻找不在基线中的变量。 Newly-seen variables get split (carefully) and put into the bash dictionary.新看到的变量被拆分(小心地)并放入bash字典中。 I've left here (but commented-out) my previous idea for using exec to set the variables natively in python, but I ran into quoting/escaping issues, so I switched gears to using a dict.我已经离开(但注释掉了)我之前使用exec在 python 中本地设置变量的想法,但我遇到了引用/转义问题,所以我切换到使用 dict 。

If the exact call (path, etc) to your "variables" file is different than mine, then you'll need to change all of the instances of that value -- in the subprocess.check_output() call, in the list.remove() calls.如果对“变量”文件的确切调用(路径等)与我的不同,那么您需要更改该值的所有实例——在list.remove() subprocess.check_output()调用中,在list.remove()调用。

Here's the sample variable file I was using, just to demonstrate some of the things that could happen:这是我使用的示例变量文件,只是为了演示一些可能发生的事情:

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"

... and here's the python script: ...这是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]

Another way to do it:另一种方法:

Inspired by Marat 's answer, I came up with this two-stage hack.受到Marat回答的启发,我想出了这个两阶段的 hack。 Start with a python program, let's call it "stage 1", which uses subprocess to call bash to source the variable file, as my above answer does, but it then tells bash to export all of the variables, and then exec the rest of your python program, which is in "stage 2".从 python 程序开始,我们称之为“阶段 1”,它使用subprocess调用 bash 来获取变量文件,正如我上面的答案所做的那样,但它然后告诉 bash 导出所有变量,然后执行其余的您的 Python 程序,处于“第 2 阶段”。

Stage 1 python program:第 1 阶段 python 程序:

#!/usr/bin/env python

import subprocess

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

Stage 2 python program:第 2 阶段 python 程序:

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

As stated in @theorifice answer, the trick here may be that such formatted file may be interpreted by both as bash and as python code.正如@theorifice 回答中所述,这里的技巧可能是这种格式化的文件可以被解释为 bash 和 python 代码。 But his answer is outdated.但他的回答已经过时了。 imp module is deprecated in favour of importlib .不推荐使用imp模块以支持importlib

As your file has extension other than ".py", you can use the following approach:由于您的文件具有“.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)

I do not completely understand how this code works (where there are these foobar parameters), however, it worked for me.我不完全理解这段代码是如何工作的(有这些 foobar 参数的地方),但是,它对我有用。 Found it here .在这里找到

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM