subprocess.call不等待进程完成

时间:2013-04-29 18:43:04

标签: python subprocess

根据Python文档,subprocess.call应该阻塞并等待子进程完成。在此代码中,我尝试通过在命令行上调用xls将少量Libreoffice文件转换为新格式。我假设对子进程调用的调用是阻塞的,但似乎我需要在每次调用后添加一个人工延迟,否则我会错过out目录中的几个文件。

我做错了什么?为什么我需要延迟?

from subprocess import call

for i in range(0,len(sorted_files)):
            args = ['libreoffice', '-headless', '-convert-to',
                    'xls', "%s/%s.xls" %(sorted_files[i]['filename'],sorted_files[i]['filename']), '-outdir', 'out']
            call(args)
            var = raw_input("Enter something: ") # if comment this line I dont get all the files in out directory

编辑通过以下评论可能很难找到答案。我使用unoconv进行文档转换,这是一种阻止,并且易于使用脚本。

3 个答案:

答案 0 :(得分:5)

可能可能libreoffice被实现为某种守护进程/中间进程。 “守护进程”将(有效地 1 )解析命令行,然后将工作分配给其他进程,可能会将它们分离,以便它可以立即退出。 (基于documentation中的-invisible选项,我强烈怀疑这确实是你的情况。

如果是这种情况,那么你的subprocess.call确实做了广告宣传的事情 - 等待守护进程完成后再继续。但是,它不会做你想要的等待所有工作完成的事情。您在该场景中唯一的选择是查看守护程序是否具有-wait选项或类似选项。


1 这里可能没有实际守护程序,只有行为相似的东西。见comments by abernert

答案 1 :(得分:3)

问题是soffice命令行工具(libreoffice只是一个链接,或者是另一个包装器)只是真实程序的{“控制器”{{1 }}。它找到soffice.bin的正在运行的副本和/或创建on,告诉它做一些工作,然后退出。

所以,soffice.bin正在做正确的事情:它等待call退出。

但您不想等待libreoffice退出,您希望等待libreoffice完成soffice.bin要求它完成的工作。

看起来你正在尝试做的事情是不可能直接 。但是可以间接

docs说无头模式:

  

...允许在没有用户界面的情况下使用该应用程序。

     

当应用程序由外部客户端通过API控制时,可以使用此特殊模式。

换句话说,在运行一些UNO字符串/进行一些转换/在命令行上指定的任何其他内容后,应用程序不会退出,它会等待来自外部的更多UNO命令,而启动器只是快速运行因为它将适当的命令发送到应用程序。


您可能必须直接使用上述外部控制API(UNO)。

请参阅Scripting LibreOffice了解基础知识(尽管有关于内部脚本的信息比外部更多的信息),以及API documentation的详细信息和示例。

但是可能有一个更简单的答案:unoconv是一个使用UNO API编写的简单命令行工具,它完全符合您的要求。如有必要,它会启动LibreOffice,发送一些命令,等待结果,然后退出。因此,如果您只使用libreoffice代替unoconv,则只需libreoffice

另请注意call是用Python编写的,旨在用作模块。如果您只是unoconv,那么您可以编写自己的(更简单,特定于用例)代码来替换"Main entrance"代码,而根本不使用import。 (或者,当然,您可以撕开模块并自己使用相关代码,或者只是将它用作从Python中使用UNO的非常好的示例代码。)

此外,上面链接的subprocess页面列出了各种其他类似工具,其中一些通过UNO工作,另一些则不工作,因此如果它不适合您,请尝试其他工具。


如果没有其他工作,你可以考虑,例如,创建一个sentinel文件和使用文件系统监视,所以至少你将能够准确地检测它何时完成其工作,而不必猜测超时。但这是一个真正的最后沟通解决方案,除非取消所有其他选项,否则你不应该考虑。

答案 2 :(得分:0)

如果libreoffice正在使用@mgilson所提到的中介(守护进程),那么一个解决方案是找出它正在调用的程序,然后直接自己调用它。