【问题标题】:How to capture Python interpreter's and/or CMD.EXE's output from a Python script?如何从 Python 脚本中捕获 Python 解释器和/或 CMD.EXE 输出?
【发布时间】:2010-09-06 16:45:56
【问题描述】:
  1. 是否可以从 Python 脚本中捕获 Python 解释器的输出?
  2. 是否可以从 Python 脚本捕获 Windows CMD 的输出?

如果是这样,我应该查看哪个图书馆(y|ies)?

【问题讨论】:

    标签: python windows cmd


    【解决方案1】:

    我想我可以为你的问题的第一部分指出一个很好的答案。

    1.是否可以从 Python 捕获 Python 解释器的输出 脚本?

    答案是“”,我个人喜欢PEP 343 -- The "with" Statement文档中的示例中的以下内容。

    from contextlib import contextmanager
    import sys
    
    @contextmanager
    def stdout_redirected(new_stdout):
        saved_stdout = sys.stdout
        sys.stdout = new_stdout
        try:
            yield None
        finally:
            sys.stdout.close()
            sys.stdout = saved_stdout
    

    并像这样使用:

    with stdout_redirected(open("filename.txt", "w")):
        print "Hello world"
    

    它的一个很好的方面是它可以选择性地应用于脚本执行的一部分,而不是整个范围,并且即使在其上下文中引发未处理的异常时也保持有效。如果您在第一次使用后以附加模式重新打开文件,您可以将结果累积到一个文件中:

    with stdout_redirected(open("filename.txt", "w")):
        print "Hello world"
    
    print "screen only output again"
    
    with stdout_redirected(open("filename.txt", "a")):
        print "Hello world2"
    

    当然,上述内容也可以扩展为将sys.stderr 重定向到同一个文件或另一个文件。另请参阅此answer 相关问题。

    【讨论】:

      【解决方案2】:

      其实你绝对可以,而且漂亮、丑陋、疯狂并存!

      您可以将 sys.stdout 和 sys.stderr 替换为收集输出的 StringIO 对象。

      这是一个例子,保存为 evil.py:

      import sys
      import StringIO
      
      s = StringIO.StringIO()
      
      sys.stdout = s
      
      print "hey, this isn't going to stdout at all!"
      print "where is it ?"
      
      sys.stderr.write('It actually went to a StringIO object, I will show you now:\n')
      sys.stderr.write(s.getvalue())
      

      当你运行这个程序时,你会看到:

      • stdout(通常打印到的地方)没有任何内容
      • 写入 stderr 的第一个字符串是以 'It' 开头的字符串
      • 接下来的两行是在 StringIO 对象中收集的行

      像这样替换 sys.stdout/err 是所谓的猴子补丁的应用程序。无论这是否“支持”,意见可能会有所不同,这绝对是一个丑陋的黑客,但它在尝试包裹外部东西一两次时救了我的培根。

      在 Linux 上测试,而不是在 Windows 上测试,但它应该也能正常工作。让我知道它是否适用于 Windows!

      【讨论】:

        【解决方案3】:

        如果您正在谈论作为脚本“父级”的 python 解释器或 CMD.exe,那么不,这是不可能的。在每个类似 POSIX 的系统中(现在您似乎正在运行 Windows,这可能有一些我不知道的怪癖,YMMV)每个进程都有三个流,标准输入、标准输出和标准错误。 Bu 默认(在控制台中运行时)这些被定向到控制台,但可以使用管道符号进行重定向:

        python script_a.py | python script_b.py
        

        这将脚本 a 的标准输出流与脚本 B 的标准输入流联系起来。在此示例中,标准错误仍会发送到控制台。请参阅 Wikipedia 上有关 standard streams 的文章。

        如果你在谈论一个子进程,你可以像这样从 python 启动它(如果你想要双向通信,stdin 也是一个选项):

        import subprocess
        # Of course you can open things other than python here :)
        process = subprocess.Popen(["python", "main.py"], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
        x = process.stderr.readline()
        y = process.stdout.readline()
        process.wait()
        

        有关管理进程的信息,请参阅 Python subprocess 模块。对于通信,process.stdin 和 process.stdout 管道被认为是标准的file objects

        对于管道使用,从标准输入读取 lassevk 建议您执行以下操作:

        import sys
        x = sys.stderr.readline()
        y = sys.stdin.readline()
        

        sys.stdin 和 sys.stdout 是如上所述的标准文件对象,在sys 模块中定义。您可能还想看看pipes 模块。

        在我的示例中使用 readline() 读取数据是一种非常幼稚的获取数据的方式。如果输出不是面向行或不确定的,您可能想查看polling,不幸的是它在 Windows 中不起作用,但我确信那里有一些替代方案。

        【讨论】:

        • 请注意,当使用 subprocess.Popen() 调用 Python 时,传递“-u”标志通常很有帮助,它会禁用 stdin/stdout/stderr 上的缓冲。当孩子开始读取标准输入时,Python 不会自动刷新标准输出,如果输出已被重定向到管道,因此您最终可能会永远阻止读取缓冲的输出。我在尝试包装/自动化 pdb 时遇到了这个问题。
        【解决方案4】:

        你想要subprocess。具体看17.1.1的Popen,17.1.2的通信。

        【讨论】:

          【解决方案5】:

          你是在什么情况下问的?

          您是否尝试从您在命令行启动的程序中捕获输出?

          如果是这样,那么这就是如何执行它:

          somescript.py | your-capture-program-here
          

          要读取输出,只需从标准输入读取。

          另一方面,如果您正在程序中执行该脚本或 cmd.exe 或类似文件,并且想要等到脚本/程序完成并捕获其所有输出,那么您需要查看在您用于启动该外部程序的库调用中,很可能有一种方法可以要求它为您提供一些方法来读取输出并等待完成。

          【讨论】:

            猜你喜欢
            • 2020-10-26
            • 1970-01-01
            • 1970-01-01
            • 2011-08-21
            • 1970-01-01
            • 2018-01-06
            • 1970-01-01
            • 2012-01-11
            • 1970-01-01
            相关资源
            最近更新 更多