【问题标题】:Python subprocess.call not waiting for process to finish blenderPython subprocess.call 不等待进程完成搅拌机
【发布时间】:2026-01-27 03:25:01
【问题描述】:

我在搅拌机中有一个 python 脚本

subprocess.call(os.path.abspath('D:/Test/run-my-script.sh'),shell=True)

随后是许多其他代码,这些代码依赖于这个 shell 脚本来完成。发生了什么是它不等待它完成,我不知道为什么?我什至尝试使用Popen 而不是call,如图所示:

p1 = subprocess.Popen(os.path.abspath('D:/Test/run-my-script.sh'),shell=True)
p1.wait()

我尝试使用 commuincate 但它仍然不起作用:

p1 = subprocess.Popen(os.path.abspath('D:/Test/run-my-script.sh'),shell=True).communicate()

此 shell 脚本在 MacOS 上运行良好(更改路径后)并在使用 subprocess.call(['sh', '/userA/Test/run-my-script.sh']) 时等待

但在 Windows 上会发生这种情况,我在 Blender 中运行下面的 python 脚本,然后一旦它到达子进程行 Git bash 打开并运行 shell 脚本,而 Blender 不等待它完成它只是打印Hello 在其控制台中,无需等待 Git Bash 完成。有什么帮助吗?

import bpy
import subprocess
subprocess.call(os.path.abspath('D:/Test/run-my-script.sh'),shell=True)
print('Hello')

【问题讨论】:

  • 当您从命令行运行D:/Test/run-my-script.sh 时,Windows 上会发生什么?它会立即返回吗?
  • 你能发布 bash 脚本吗?

标签: python shell subprocess blender git-bash


【解决方案1】:

您可以使用subprocess.call 来做到这一点。

subprocess.call(args, *, stdin=None, stdout=None, stderr=None, shell=False, timeout=None)

运行 args 描述的命令。等待命令完成,然后返回 returncode 属性。

编辑:我想我对正在发生的事情有预感。该命令适用于您的 Mac,因为我相信 Mac 支持开箱即用的 Bash(至少在功能上等效),而在 Windows 上,它会看到您尝试运行“.sh”文件并触发我认为 Git Bash 在启动时会执行几次分叉。

由于这个 Python 认为你的脚本已经完成,PID 就消失了。

如果我是你,我会这样做:

  • 使用tempfile 模块在“启动”脚本中生成唯一的、不存在的绝对路径。
  • 启动脚本时,将刚刚创建的路径作为参数传递。
  • 脚本启动时,让它在路径中创建一个文件。完成后,删除文件。
  • 启动脚本应注意该文件的创建和删除以指示脚本的状态。

希望这是有道理的。

【讨论】:

  • 在某些情况下这不起作用。例如,在我的情况下,该过程是一个创建文件的程序,然后它访问该文件以在一段时间内修改其内容。 subprocess.call 将过程视为已完成,当文件创建时程序仍在修改文件的内容并且过程仍在进行中。有什么解决方法吗?
  • @SeF 然后你做了一些意想不到的事情——文档非常明确地说明了函数是如何工作的。也许您正在分叉或执行另一个进程?
【解决方案2】:

您可以使用 Popen.communicate API。

p1 = subprocess.Popen(os.path.abspath('D:/Test/run-my-script.sh'),shell=True)
sStdout, sStdErr = p1.communicate()

命令

Popen.communicate(input=None, timeout=None)

与进程交互:将数据发送到标准输入。从 stdout 和 stderr 读取数据,直到到达文件结尾。等待进程终止。

【讨论】:

  • 感谢所有参与赏金的人,这个答案提出了一个替代等待命令的方法,它似乎并不总是有效。
【解决方案3】:

subprocess.run 默认会等待进程完成。

【讨论】:

  • 你的问题给我的印象是你使用的是subprocess.Popen 而不是subprocess.run 使用run 时它不等待吗?
  • 我使用了 subprocess.run 也没有等待
  • 如果您使用os.spawn 方法之一并将os.P_WAIT 作为第一个参数会发生什么?
  • “作为第一个参数”是什么意思?
  • 第一个参数。在您尝试调用的命令的参数之前。这是启动进程并告诉 python 等待它完成的旧方法。例如os.spawn(os.P_WAIT, "run_my_script.sh")
【解决方案4】:

使用 subprocess.PopenPopen.wait

process = subprocess.Popen(['D:/Test/run-my-script.sh'],shell=True, executable="/bin/bash")
process.wait()

您也可以使用check_call() 代替 Popen。

【讨论】:

    【解决方案5】:

    你可以使用os.system,像这样:

    import bpy
    import os
    os.system("sh "+os.path.abspath('D:/Test/run-my-script.sh'))
    print('Hello')
    

    【讨论】:

    • os.system 在某些情况下很好,但并非总是如此。他可能只是在调用他的二进制文件时出错,所以建议使用 os.system 并不重要。
    【解决方案6】:

    显然有一些运行命令失败的情况。 这是我的解决方法:

    def check_has_finished(pfi, interval=1, timeout=100):
        if os.path.exists(pfi):
            if pfi.endswith('.nii.gz'):
                mustend = time.time() + timeout
                while time.time() < mustend:
                    try:
                        # Command is an ad hoc one to check if the process  has finished.
                        subprocess.check_output('command {}'.format(pfi), shell=True)
                    except subprocess.CalledProcessError:
                        print "Caught CalledProcessError"
                    else:
                        return True
                    time.sleep(interval)
                msg = 'command {0} not working after {1} tests. \n'.format(pfi, timeout)
                raise IOError(msg)
            else:
                return True
        else:
            msg = '{} does not exist!'.format(pfi)
            raise IOError(msg)
    

    【讨论】:

      【解决方案7】:

      尝试一下,但是您是以管理员身份运行 shell 而 Blender 以普通用户身份运行,反之亦然?

      长话短说(非常短),Windows UAC 是一种介于管理员和普通用户之间的隔离环境,因此可能会发生这种随机的怪癖。不幸的是,我不记得它的来源,我找到的最接近的是this

      我的问题与你的完全相反,wait() 陷入了无限循环,因为我的 python REPL 是从管理 shell 触发的,并且无法读取常规用户子进程的状态。恢复到普通用户 shell 可以修复它。这不是我第一次被 UAC 搞砸了。

      【讨论】: