Python subprocess.call 不等待进程完成搅拌机

Posted

技术标签:

【中文标题】Python subprocess.call 不等待进程完成搅拌机【英文标题】:Python subprocess.call not waiting for process to finish blender 【发布时间】:2017-09-07 13:18:25 【问题描述】:

我在搅拌机中有一个 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 脚本吗? 【参考方案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 搞砸了。

【讨论】:

以上是关于Python subprocess.call 不等待进程完成搅拌机的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 python 2.7.6 使 subprocess.call 超时?

在 Python 中使用 subprocess.call 播放音频

Python执行外部命令(subprocess,call,Popen)

Python下的subprocess.call()使用和注意事项

如何在 python 中杀死使用 subprocess.call 调用的子进程? [复制]

三十python 中subprocess介绍