pythonselect函数,
您可以使用子流程来完成这项工作,但这并不简单。如果您查看文档中经常使用的参数,您会看到管道可以作为stderr参数传递,这将创建一个新管道,将管道的一端传递给子进程,并使另一端作为stderr属性可用。*
因此,您需要服务于这个管道,并写入屏幕和文件。一般来说,很难得到正确的细节。* *在您的情况下,只有一个管道,并且您计划同步维护它,所以它并没有那么糟糕。导入子流程
proc=子进程。Popen([路径_到_工具,-选项1 ,选项2],
stdout=file_out,stderr=subprocess。管道)
对于proc.stderr中的行:
sys.stdout.write(行)
log_file.write(行)
proc.wait()
(请注意,在proc.stderr中使用for line:有些问题3354基本上,如果你读取的内容因为任何原因不是行缓冲,那么你可以坐在那里等待行换行,即使实际上有半行数据需要处理。可以一次性读取数据块,比如read(128)甚至read(1),以便在需要的时候更流畅的获取数据。如果您需要在每个字节到达后立即获取它,并且负担不起read(1)的开销,那么您需要将管道置于非阻塞模式并异步读取。)
但是如果您使用的是Unix,使用tee命令可能会更简单。
对于快速脏的解决方案,可以使用shell打通管道。像这样:subprocess . call( path _ to _ tool-option 1 option 2 2 teelog _ file 12 ,shell=true,
stdout=file_out)
但是我不想调试壳管;我们用Python来做吧,比如在docs:tool=subprocess . popen([ path _ to _ tool ,-option 1 , option 2],
stdout=file_out,stderr=subprocess。管道)
tee=子流程。Popen([tee , log_file],stdin=tool.stderr)
tool.stderr.close()
tee.communicate()
最后,PyPI-sh、shell、shell_command、shellout、iterpipes、sarge、cmd_utils、commandwrapper和其他子进程和/或shell上有十几个更高级别的包装器。搜索“shell”、“子进程”、“命令行”,找到一个你喜欢的包装器,让问题变得简单。
如果需要同时收集stderr和stdout怎么办?
简单的方法就是把一个重定向到另一个,就像斯文马纳赫在评论中建议的那样。只需更改Popen参数如下:tool=subprocess . Popen([ path _ to _ tool ,-option1 , option2],
stdout=子进程。管道,stderr=子进程。STDOUT)
那么在任何使用tool.stderr的地方,都可以使用tool.stdout,比如最后一个例子:tee=subprocess.popen ([tee , log _ file],stdin=tool.stdout)
tool.stdout.close()
tee.communicate()
但是也有一些权衡。最明显的是,将这两个流混合在一起意味着不能将stdout记录到file_out,将stderr记录到log_file,或者将stdout复制到stdout,将stderr复制到stderr。但这也意味着,如果子进程总是在向stdout写入任何内容之前向stderr写入两行,那么顺序可能是不确定的。一旦流被混合,您可能会在这两行之间得到一堆输出。这意味着它们必须共享stdout的缓冲模式,所以如果你依赖linux/glibc来确保stderr是行缓冲的(除非子进程显式地改变它),那么这可能不再成立。
如果这两个过程需要分开处理,就会变得更加困难。前面我说过,只要你只有一条管道,并且能同步修复,那么在飞行中修复管道是很容易的。如果你有两个管道,这显然不再是真的。假设您正在等待tool.stdout.read()并且新数据来自tool.stderr如果数据太多,管道可能会溢出,子进程可能会被阻塞。然而,即使没有发生这种情况,很明显,在stdout提供一些信息之前,您将无法读取和记录stderr数据。
如果您使用管道直通三通解决方案,您可以避免最初的问题…但只能通过创建一个同样糟糕的新项目。您有两个tee实例,当您在其中一个上调用communicate时,另一个实例一直在等待。
所以,不管怎样,你都需要某种异步机制。你可以用线程,一个选择反应器,像gevent这样的东西。
下面是一个快速而肮脏的例子:proc=subprocess . popen([ path _ to _ tool ,-option 1 , option 2],
stdout=子进程。管道,stderr=子进程。管道)
定义三通_管道(管道,f1,f2):
对于管道中的管线:
f1.write(行)
f2 .写(行)
t1=线程。Thread(target=tee_pipe,args=(proc.stdout,file_out,sys.stdout))
t2=线程。Thread(target=tee_pipe,args=(proc.stderr,log_file,sys.stderr))
t3=线程。线程(进程等待)
t1 . start();T2 . start();t3.start()
t1 . join();T2 . join();t3.join()
然而,在某些边缘情况下,这是行不通的。(问题是SIGCHLD和SIGPIPE/eppe/EOF的到达顺序。我不认为所有这些会影响我们,因为我们不会发送任何输入…但不要不加思考和/或测试就相信我。)3.3中的{}函数可以正确获取所有细节。但是,您可能会发现在PyPI和ActiveState上使用异步子流程包装器要简单得多,甚至在Twisted这样的成熟异步框架中使用子流程也要简单得多。
*文档并没有真正解释什么是管道,就像他们希望你是一个Unix C老手一样…但是一些例子,尤其是在用{}模块替换旧函数一节中,展示了它们的使用方法,而且非常简单。
* *最困难的部分是正确分类两个或更多管道。如果您在一个管道上等待,另一个管道可能会溢出并被阻塞,从而阻止您在另一个管道上等待。解决这个问题的唯一简单方法是创建一个线程来为每个管道提供服务。(在大多数*nix平台上,您可以使用选择或轮询反应器,但是这使得跨平台非常困难。)模块的源代码,尤其是communicate及其助手,展示了如何做到这一点。(我链接到3.3,因为在早期版本中,通信本身会出错.)这就是为什么,只要有可能,如果需要多个管道,就使用communicate。在您的示例中,您不能使用communicate,但幸运的是,您不需要多个管道。
郑重声明:本文由网友发布,不代表盛行IT的观点,版权归原作者所有,仅为传播更多信息之目的,如有侵权请联系,我们将第一时间修改或删除,多谢。