【问题标题】:How do we call bash functions from python我们如何从 python 调用 bash 函数
【发布时间】:2018-12-10 05:31:13
【问题描述】:

假设我有一个 bash 函数,我将它输入到 shell 中。

# cat sample.sh 
function func()
{
    echo "Custom env : $CUSTOM_ENV"
}

现在我在 bash shell 中获取这个脚本: #source sample.sh

然后我定义:

export CUSTOM_ENV="abc"

然后从 bash shell 调用 func(),它显示:

#func
Custom env : abc

现在,如果我从同一个 shell 调用 python 脚本, 我想从 python 脚本调用函数 func() 。无论如何要做到这一点?

我尝试了什么:

  1. 试过 os.system('func') - 不起作用
  2. 试过 subprocess.check_output('func', shell=True, env=os.environ.copy()) - 不起作用

有什么指导吗?

【问题讨论】:

  • 要么在 Python 中重新编码(即使用字符串表示并调用它),要么调用 bash sample.sh
  • 调用 bash sample.sh 似乎不起作用。试过了:)
  • 另见stackoverflow.com/a/49209211/874188(可能重复,但细节不同)。

标签: python bash shell subprocess


【解决方案1】:

您遇到的问题是涉及两个单独的 bash 进程:

  • 外部 bash -> 了解 func,运行 python
  • Python,当您调用os.systemsubprocess.check_output 时运行一个新的bash 进程
  • 内部 bash -> 由 Python 创建,与外部 bash 完全不同。

您在外部 bash 中所做的任何事情都无法被内部 bash 访问。您需要将该函数提供给内部 bash。

类似: subprocess.check_call("bash -c '. sample.sh && func'", shell=True)

这可能不完全正确,但希望您能明白 - 您希望 Python 创建的内部 bash 在尝试运行 func 之前了解该函数。

(特别是在这段代码中,第三个 shell 可能会生成一个 fourth shell - 这样更容易,但如果你关心性能,你可能希望稍微调整一下。)

【讨论】:

    【解决方案2】:

    您需要export 函数(使用-f 选项):

    $ function func()
    > {
    >     echo "Custom env : $CUSTOM_ENV"
    > }
    $ export -f func
    $ export CUSTOM_ENV="abc"
    $ python
    Python 2.7.10 (default, Oct  6 2017, 22:29:07) 
    [GCC 4.2.1 Compatible Apple LLVM 9.0.0 (clang-900.0.31)] on darwin
    Type "help", "copyright", "credits" or "license" for more information.
    >>> import os
    >>> os.system('func')
    Custom env : abc
    0
    

    请注意,exporting 函数(和变量)会将函数和变量的副本导出到它们从中导出的 shell 的子进程中。它们在父(或兄弟)进程中不可用。此外,在子流程中更改它们不会影响原始副本。

    另外,导出函数只是 bash 的事情,所以这只有在父 shell 和从 python 启动的 shell 都是 bash 时才有效。在 bash 不是默认设置的操作系统上(例如,最新版本的 Ubuntu 和 Debian),您需要显式运行 bash,否则它将无法工作。这一切都使它变得相当脆弱,正如@triplee 指出的那样,这不是一个好主意。

    【讨论】:

    • 这回答了问题,但您可以这一事实并不意味着您应该。
    【解决方案3】:

    在你非常具体的例子中:

    import subprocess
    import os
    
    def run_bash(cmd):
        subprocess.Popen(['/bin/bash', '-c', cmd])
    
    #run_bash('ls -ltra')
    #run_bash("date '+%A %W %Y %X'")
    
    os.environ["CUSTOM_ENV"] = "MJ"
    run_bash('./sample.sh')
    

    确保 sample.sh 由chmod +x sample.sh 执行

    test_bash.py 是:

    import subprocess
    
    def run_bash(cmd):
        subprocess.Popen(['/bin/bash', '-c', cmd])
    
    run_bash('ls -ltra')
    run_bash("date '+%A %W %Y %X'")
    

    $ python test_bash.py 
    Monday 50 2018 12:47:13 AM
    total 668
    -rw-r--r--. 1 jalal cs-grad   2590 Nov  4 16:46 data_loading.py
    drwxr-xr-x. 8 jalal cs-grad    211 Nov  4 16:46 .git
    drwxr-xr-x. 2 jalal cs-grad     85 Nov  4 22:44 .ipynb_checkpoints
    

    【讨论】:

    • 如果可以避免使用subprocess.Popen,则不要使用它,尤其是不要以这种方式,让悬空的子进程不受管理。另见stackoverflow.com/a/51950538/874188
    猜你喜欢
    • 1970-01-01
    • 2016-02-01
    • 2019-09-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-09-28
    • 1970-01-01
    相关资源
    最近更新 更多