我有一个Python脚本,其中调用了JAR。调用JAR后,将调用两个shell脚本。最初我这样做:
proc = subprocess.Popen(jar_command, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
proc.wait()
output, errors = proc.communicate()
proc = subprocess.Popen(prune_command, shell=True)
proc.wait()
proc = subprocess.call(push_command, shell=True)
我必须等待前两个进程完成,所以我使用Popen()
,最后一个我可以让它在后台运行,所以我call()
。我传递shell=True
因为我希望被调用的shell脚本能够访问环境变量。
但是,上面的工作,我没有从JAR进程中获取任何日志记录。我试过这样称呼它:
proc = subprocess.call(jar_command)
这会按照我的预期记录,但后面的两个shell脚本不会被执行。最初我认为日志不是stdout
,但事实证明它们根本没有被执行。 I.E.不删除多余的文件或推送到数据库。
为什么要忽略后续shell脚本?
答案 0 :(得分:3)
如果您某些您的shell脚本根本没有运行,并且第一个代码一切正常 - 那么它必须 java命令死锁或不正确终止使用call()
函数。
您可以通过在bash脚本中添加虚拟文件来验证这一点。把它放在脚本的第一行,所以如果它被执行,你将获得创建的虚拟文件。如果它没有被创建,那意味着脚本没有被执行,可能是因为java执行的东西。
我会尝试几件事:
首先,我会返回Popen
而不是call
。不要使用wait()
,而是使用communicate()
:
与流程交互:将数据发送到stdin。从stdout和stderr读取数据,直到达到文件结尾。 等待进程终止。 communic()返回元组(stdoutdata,stderrdata)。
proc = subprocess.Popen(jar_command, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
proc.communicate()
确保检查两个数据流(stdout和stderr)。您可能会错过java进程引发的错误。
接下来,我会尝试通过向bufsize=0
提供Popen
来禁用缓冲区。它将消除与python缓冲相关的选项。
如果两个选项仍然不起作用,请尝试使用check_call()
查看是否存在例外:
proc = subprocess.check_call(jar_command)
使用参数运行命令。等待命令完成。如果返回代码为零则返回,否则提升 CalledProcessError 。
这些选项可能有答案;如果没有,他们会帮助调试过程。随意评论这一进展如何。
答案 1 :(得分:0)
最有可能的是,您忘记了进程流实际上是具有一定容量的OS级缓冲区。
例如,如果你运行一个在PIPE模式下产生大量输出的进程,并且在尝试使用该进程写入输出的任何内容之前等待它完成,那么就会出现死锁:
正确的方法是在程序中启动一个线程,以便排出"排除"当进程运行并且主线程正在等待时,管道会不断进行。您必须先启动流程,然后启动排水螺纹,然后等待流程完成。
对于差分诊断,检查子进程是否运行良好且输出很少(即只要缓冲区没有填满,例如一行或两行)。
子流程的文档有关于此的note。