【问题标题】:Set environment variable of calling bash script in python [duplicate]在python中设置调用bash脚本的环境变量[重复]
【发布时间】:2018-08-18 10:54:11
【问题描述】:

我有一个如下所示的 bash 脚本:

python myPythonScript.py

python myOtherScript.py $VarFromFirstScript

myPythonScript.py 看起来像这样:

print("Running some code...")
VarFromFirstScript = someFunc()
print("Now I do other stuff")

问题是,我如何将变量 VarFromFirstScript 返回到名为 myPythonScript.py 的 bash 脚本。

我尝试了os.environ['VarFromFirstScript'] = VarFromFirstScript,但这不起作用(我认为这意味着 python 环境与调用 bash 脚本的环境不同)。

【问题讨论】:

  • 不能更改其他进程的环境变量。您只能在启动进程时影响它们,因此不能选择环境变量。这留下了各种其他 IPC 方式,但最自然的一种可能是写信给stdout
  • 所以鉴于 python 脚本有一堆打印语句,我只需要在 bash 中解析所有这些语句以获得我想要的 export 语句?
  • 为什么它有所有这些print() 调用(不是语句,不是在 Python 3 中!)?我想这是为了记录,对吧?在这种情况下,首先,使用日志库,然后您也可以使用它来记录到文件。其次,不要使用 stdout 而是使用 stderr,它通常用于非有效负载、非正式输出。

标签: python bash environment-variables


【解决方案1】:

您不能将环境变量传播到父进程。但是您可以打印变量,然后从您的 shell 将其分配回变量名:

VarFromFirstScript=$(python myOtherScript.py $VarFromFirstScript)

您不得在代码中打印任何其他内容,或使用stderr

sys.stderr.write("Running some code...\n")
VarFromFirstScript = someFunc()
sys.stdout.write(VarFromFirstScript)

另一种方法是创建一个包含要设置的变量的文件,并使其由您的 shell 解析(您可以创建一个父 shell 将 source 的 shell)

import shlex
with open("shell_to_source.sh","w") as f:
   f.write("VarFromFirstScript={}\n".format(shlex.quote(VarFromFirstScript))

shlex.quote 允许避免来自 python 的代码注入,由 Charles Duffy 提供)

那么在调用python之后:

source ./shell_to_source.sh

【讨论】:

  • 这应该是 pipes.quote(VarFromFirstScript)(或者,在 Python 3 中,shlex.quote(...))以避免安全问题。
  • 写入标准输出也很常见——考虑ssh-agent 预计如何通过eval "$(ssh-agent -s)" 调用其输出。写入文件和source 文件的建议在这里似乎是不必要的。
  • 好的,但是这个方法允许改变几个变量。
  • 我不确定我是否明白你在说什么。 eval 方法和source 方法在这方面是相同的; ssh-agent 肯定设置了多个变量。请记住,您可以eval 包含文字换行符的代码的字符串。
【解决方案2】:

您只能将环境变量从父进程传递给子进程。

创建子进程时,环境块复制到子进程 - 子进程有一个副本,因此子进程中的任何更改只会影响子进程的副本(以及它的任何其他子进程)创建)。

要与父级通信,最简单的方法是在我们捕获stdout 的bash 中使用命令替换

Bash 脚本:

#!/bin/bash
var=$(python myPythonScript.py)
echo "Value in bash: $var"

Python 脚本:

print("Hollow world!")

示例运行:

$ bash gash.sh
Value in bash: Hollow world!

您在 python 中有其他打印语句,您需要过滤出您需要的数据,可能通过使用众所周知的前缀标记数据。

如果你在 python 中有很多 print 语句,那么这个解决方案是不可扩展的,所以你可能需要使用进程替换,像这样:

Bash 脚本:

#!/bin/bash

while read -r line
do
    if [[ $line = ++++* ]]
    then
        # Strip out the marker
        var=${line#++++}
    else
        echo "$line"
    fi
done < <(python myPythonScript.py)

echo "Value in bash: $var"

Python 脚本:

def someFunc():
    return "Hollow World"

print("Running some code...")

VarFromFirstScript = someFunc()
# Prefix our data with a well-known marker
print("++++" + VarFromFirstScript)

print("Now I do other stuff")

示例运行:

$ bash gash.sh
Running some code...
Now I do other stuff
Value in bash: Hollow World

【讨论】:

    【解决方案3】:

    我会获取您的脚本,这是最常用的方法。这会在当前 shell 下执行脚本,而不是加载另一个脚本。因为这使用了您设置的相同 shell 环境变量,所以在它退出时将可以访问它。 . /path/to/script.shsource /path/to/script.sh 都可以工作,.source 有时不工作的地方工作。

    【讨论】:

    • 如果该代码只是一个 shell 脚本。但是你不能获取 Python 代码。
    • 是的,那么使用子进程从 python 脚本创建 bash 环境变量?
    • 据我了解,BASH 已经作为父进程运行,无法更改其他进程的环境变量。
    猜你喜欢
    • 2021-08-29
    • 2015-10-04
    • 2013-11-15
    • 2016-10-07
    • 2019-01-05
    • 1970-01-01
    • 2012-01-12
    • 2020-04-05
    • 2021-04-10
    相关资源
    最近更新 更多