windows 如何从 Python 脚本中捕获 Python 解释器和/或 CMD.EXE 的输出?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/24931/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-15 11:07:17  来源:igfitidea点击:

How to capture Python interpreter's and/or CMD.EXE's output from a Python script?

pythonwindowscmd

提问by guillermooo

  1. Is it possible to capture Python interpreter's output from a Python script?
  2. Is it possible to capture Windows CMD's output from a Python script?
  1. 是否可以从 Python 脚本中捕获 Python 解释器的输出?
  2. 是否可以从 Python 脚本中捕获 Windows CMD 的输出?

If so, which librar(y|ies) should I look into?

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

回答by Henrik Gustafsson

If you are talking about the python interpreter or CMD.exe that is the 'parent' of your script then no, it isn't possible. In every POSIX-like system (now you're running Windows, it seems, and that might have some quirk I don't know about, YMMV) each process has three streams, standard input, standard output and standard error. Bu default (when running in a console) these are directed to the console, but redirection is possible using the pipe notation:

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

python script_a.py | python script_b.py

This ties the standard output stream of script a to the standard input stream of script B. Standard error still goes to the console in this example. See the article on standard streamson Wikipedia.

这将脚本 a 的标准输出流与脚本 B 的标准输入流联系起来。在此示例中,标准错误仍会转到控制台。请参阅维基百科上关于标准流的文章。

If you're talking about a child process, you can launch it from python like so (stdin is also an option if you want two way communication):

如果你在谈论一个子进程,你可以像这样从 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()

See the Python subprocessmodule for information on managing the process. For communication, the process.stdin and process.stdout pipes are considered standard file objects.

有关管理流程的信息,请参阅 Python子流程模块。对于通信, process.stdin 和 process.stdout 管道被视为标准文件对象

For use with pipes, reading from standard input as lassevksuggested you'd do something like this:

为了与管道一起使用,从标准输入中读取lassevk建议您执行以下操作:

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

sys.stdin and sys.stdout are standard file objects as noted above, defined in the sysmodule. You might also want to take a look at the pipesmodule.

sys.stdin 和 sys.stdout 是上面提到的标准文件对象,在sys模块中定义。您可能还想查看管道模块。

Reading data with readline() as in my example is a pretty na?ve way of getting data though. If the output is not line-oriented or indeterministic you probably want to look into pollingwhich unfortunately does not work in windows, but I'm sure there's some alternative out there.

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

回答by martineau

I think I can point you to a good answer for the first part of your question.

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

1.  Is it possible to capture Python interpreter's output from a Python script?

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

The answer is "yes", and personally I like the following lifted from the examples in the PEP 343 -- The "with" Statementdocument.

答案是“”,我个人喜欢从PEP 343 中的示例中提取的以下内容——“with”声明文档。

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

And used like this:

并像这样使用:

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

A nice aspect of it is that it can be applied selectively around just a portion of a script's execution, rather than its entire extent, and stays in effect even when unhandled exceptions are raised within its context. If you re-open the file in append-mode after its first use, you can accumulate the results into a single file:

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

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"

Of course, the above could also be extended to also redirect sys.stderrto the same or another file. Also see this answerto a related question.

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

回答by Thomas Vander Stichele

Actually, you definitely can, and it's beautiful, ugly, and crazy at the same time!

事实上,你绝对可以,而且它同时是美丽的、丑陋的和疯狂的!

You can replace sys.stdout and sys.stderr with StringIO objects that collect the output.

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

Here's an example, save it as evil.py:

这是一个示例,将其保存为 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())

When you run this program, you will see that:

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

  • nothing went to stdout (where print usually prints to)
  • the first string that gets written to stderr is the one starting with 'It'
  • the next two lines are the ones that were collected in the StringIO object
  • 没有任何东西进入标准输出(通常打印到的地方)
  • 写入 stderr 的第一个字符串是以“It”开头的字符串
  • 接下来的两行是在 StringIO 对象中收集的那些

Replacing sys.stdout/err like this is an application of what's called monkeypatching. Opinions may vary whether or not this is 'supported', and it is definitely an ugly hack, but it has saved my bacon when trying to wrap around external stuff once or twice.

像这样替换 sys.stdout/err 是所谓的monkeypatching 的应用程序。无论这是否被“支持”,意见可能会有所不同,这绝对是一个丑陋的黑客,但是当我试图将外部内容包裹一两次时,它已经拯救了我的培根。

Tested on Linux, not on Windows, but it should work just as well. Let me know if it works on Windows!

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

回答by Patrick

You want subprocess. Look specifically at Popen in 17.1.1 and communicate in 17.1.2.

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

回答by Lasse V. Karlsen

In which context are you asking?

你是在什么情况下问的?

Are you trying to capture the output from a program you start on the command line?

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

if so, then this is how to execute it:

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

somescript.py | your-capture-program-here

and to read the output, just read from standard input.

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

If, on the other hand, you're executing that script or cmd.exe or similar from within your program, and want to wait until the script/program has finished, and capture all its output, then you need to look at the library calls you use to start that external program, most likely there is a way to ask it to give you some way to read the output and wait for completion.

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