Tadeck 的回答可以帮助您完成大部分工作;但是剩下的一个大问题是破坏管道错误杀死了py_prog.py
。
事实证明,捕捉损坏的管道sys.stdout
是很棘手的,因为有时它们会在关闭期间发生,但为时已晚。
如果my_prog.py
比较干净,你可以用一些特殊的样板包裹它。假设为了说明的目的,它看起来像这个简单的程序:
$ cat badpipe.py
import sys
def main():
for i in range(1000):
print 'line', i
return 0
if __name__ == '__main__':
try:
sys.exit(main())
except KeyboardInterrupt:
sys.exit('\nInterrupted')
最后测试的代码__name__ == '__main__'
是——或者无论如何——我的独立 python 程序的常用样板。事实证明,根据这个答案,我可能需要更改它。
无论如何,如果我尝试用两种“坏”情况运行它,一种立即退出,另一种读取一点然后退出,它会以两种不同的方式运行。首先,通过管道输入“立即退出”:
$ python badpipe.py | (exit 0)
Traceback (most recent call last):
File "badpipe.py", line 10, in <module>
sys.exit(main())
File "badpipe.py", line 5, in main
print 'line', i
IOError: [Errno 32] Broken pipe
这就是我所期望的。但:
$ python badpipe.py | head -1
line 0
close failed in file object destructor:
sys.excepthook is missing
lost sys.stderr
哇!怪异的!:-)
事实证明,通过稍微调整我的包装器,我可以让怪异的行为 ( lost sys.stderr
)消失。head -1
而不是只是sys.exit(main())
,我需要在调用之前调用sys.stdout.flush()
(理想情况下,也许也可以sys.stderr.flush()
,但到目前为止我只测试了这么多)sys.exit
:
if __name__ == '__main__':
try:
ret = main()
except KeyboardInterrupt:
ret = '\nInterrupted'
try:
sys.stdout.flush()
finally:
sys.exit(ret)
有了这个,我现在可以可靠地抓住最外面IOError
的管道并检查是否有破损的管道。这是最终(或多或少)版本,main
再次包括:
import errno, sys
def main():
for i in range(1000):
print 'line', i
return 0
if __name__ == '__main__':
ret = 0
try:
try:
ret = main()
except KeyboardInterrupt:
ret = '\nInterrupted'
finally:
sys.stdout.flush()
except IOError as err:
if err.errno == errno.EPIPE:
sys.stderr.write('caught pipe-based IO-error\n')
ret = 123 # or whatever
else:
raise # some other I/O error; attempt to get a traceback
finally:
sys.exit(ret)
sys.stderr.write
after catchEPIPE
和 changed value 主要是为了说明——123没什么特别的ret
。另外我不知道最终是否raise
正确,因为我没有测试过。
运行这个给出:
$ python badpipe.py | (exit 0)
caught pipe-based IO-error
$ python badpipe.py | (head -1)
line 0
caught pipe-based IO-error
$
(注意:这一切都在 python 2.7 中,但 3.2 的行为类似。)
如果您可以修改,这一切都很好py_prog.py
,但是如果您不能修改呢?
在这种情况下,我建议编写一个包装脚本(无论使用哪种语言,Python 都可以正常工作)。让您的包装脚本读取其所有标准输入并将其全部复制(即写入)到标准输出,但检查(捕获)破管错误。如果发生这种情况,请更改策略:读取 stdin 的其余部分并将其丢弃,以便py_prog.py
愉快地相信它设法将所有内容发送到 stdout 并完成。您甚至可以将其写入subprocess.Popen
运行您的java scalaProg.pkg
命令并为您执行所有所需的特殊日志记录的情况。
即使您可以修改py_prog.py
,您也可能想要编写此包装器,具体取决于您想要发生的事情。
python py_prog.py | python wrap_java_thing.py
(虽然我不会为你写包装器:-))
顺便说一句,这lost sys.stderr
是一个 Python 错误,问题 11380。一个简单的方法来激怒它:python -c 'print "foo\n"*10000' | head -1