Python子进程在调用communicate()时卡住

4

背景:

我正在使用 2.7.5

我需要从Python脚本中运行子进程,等待其终止并获取输出。

该子进程运行约1000次。

为了运行子进程,我定义了一个函数:

def run(cmd):
    p = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
    (stdout, stderr) = p.communicate()
    return (p.returncode, stdout, stderr)

要执行的子进程是一个脚本,并作为run()函数的cmd参数传递。命令及其参数通过列表给出(如Popen()所预期的那样)。 问题: 过去,它总是没有任何错误地工作。但最近,Python脚本在成功执行了很多调用后,总是卡在子进程调用上。问题子进程根本没有被执行(bash脚本甚至没有启动),Python脚本被阻塞。
在使用Ctrl+C停止执行后,我找到了它卡住的点:
  [...]

  File "import_debug.py", line 20, in run
    (stdout, stderr) = p.communicate()
  File "/usr/lib64/python2.7/subprocess.py", line 800, in communicate
    return self._communicate(input)
  File "/usr/lib64/python2.7/subprocess.py", line 1401, in _communicate
    stdout, stderr = self._communicate_with_poll(input)
  File "/usr/lib64/python2.7/subprocess.py", line 1455, in _communicate_with_poll
    ready = poller.poll()
KeyboardInterrupt

我不明白为什么会出现这个问题,也不知道如何解决它。
我找到了这个SO帖子,似乎处理的是相同或等价的问题(因为键盘中断后的输出结果相同),但没有答案。
问题:这里发生了什么?我错过了什么?如何解决这个问题?

编辑:

调用方式如下:

(code, out, err) = run(["/path/to/bash_script.sh", "arg1", "arg2", "arg3"])

print out
if code:
    print "Failed: " + str(err)

这个bash脚本正在对数据进行基本处理(解压缩归档文件并对提取的数据执行某些操作)。当错误发生时,所有bash脚本指令都不会被执行。
我不能提供确切的命令、参数和内容,因为涉及公司隐私问题。

你能分享一下你尝试执行的Bash脚本吗?还有你传递作为 cmd 的内容是什么? - prithajnath
@prithajnath 我已经编辑了问题,提供了所需的信息(虽然涉及公司隐私,但我无法提供确切的代码和数据)。 - Fareanor
就我个人而言,我会检查bash脚本是否卡住了,也许是因为某个文件/目录存在并要求输入“您要覆盖吗?”等信息。 - Maurice Meyer
@MauriceMeyer 实际上,我的程序输出非常小(如果没有错误,则为1行)。但是我会在下次运行时尝试您的解决方案。感谢您的帮助。完成后我会通知您的。 - Fareanor
我已经找到了问题所在,给我的数据(要处理它们)是“损坏的”。那是解压缩程序要求替换、重命名或取消(压缩文件包含另一个同名的压缩文件...毫无意义)。由于我的脚本不会向stdin写入任何内容,因此它一直在等待响应。 - Fareanor
显示剩余2条评论
1个回答

3

你所提及的原帖作者说:“如果我将 stderr=subprocess.PIPE 改为 stderr=None,我就不会遇到这个问题。”—— 我建议你也这样做并让你的脚本正常工作。


在阅读评论部分后补充:

有一些有用的选项,你可能想要或不想使用:

-f  freshen existing files, create none
-n  never overwrite existing files         
-o  overwrite files WITHOUT prompting    

我无法这样做,因为如果出现错误,我需要能够报告 stderr。 - Fareanor
@Fareanor,你可以在你的Bash脚本中将stderr重定向到stdout - lenik
1
我已经找到了问题,给我的数据(要处理它们)是“损坏的”。那是解压缩程序要求替换、重命名或取消操作。由于我的脚本不会向标准输入写入任何内容,因此它一直在等待响应。 - Fareanor
我既不想摆脱stderr,也不想将其重定向到stdout。我想要分别处理它们。但无论如何,感谢您的建议。 - Fareanor

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接