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

时间:2021-05-17 14:06:34
  1. Is it possible to capture Python interpreter's output from a Python script?
  2. 是否有可能从Python脚本中捕获Python解释器的输出?

  3. Is it possible to capture Windows CMD's output from a Python script?
  4. 是否可以从Python脚本中捕获Windows CMD的输出?

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

如果是这样,我应该研究哪些图书馆(y | ies)?

5 个解决方案

#1


9  

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)每个进程有三个流,标准输入,标准输出和标准错误。 Bu默认(在控制台中运行时)会将这些指向控制台,但可以使用管道符号进行重定向:

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 streams on Wikipedia.

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

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 subprocess module 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 lassevk suggested 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 sys module. You might also want to take a look at the pipes module.

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 polling which unfortunately does not work in windows, but I'm sure there's some alternative out there.

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

#2


4  

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" Statement document.

答案是“是”,我个人喜欢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:

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

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.stderr to the same or another file. Also see this answer to a related question.

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

#3


3  

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)
  • 什么都没有去stdout(打印通常打印到)

  • the first string that gets written to stderr is the one starting with 'It'
  • 写入stderr的第一个字符串是以'It'开头的字符串

  • the next two lines are the ones that were collected in the StringIO object
  • 接下来的两行是在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,请告诉我!

#4


1  

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

你想要子进程。请参阅17.1.1中的Popen并在17.1.2中进行通信。

#5


0  

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或类似程序,并希望等到脚本/程序完成并捕获其所有输出,那么您需要查看库你用来启动那个外部程序的调用,很可能有一种方法可以让它给你一些方法来读取输出并等待完成。

#1


9  

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)每个进程有三个流,标准输入,标准输出和标准错误。 Bu默认(在控制台中运行时)会将这些指向控制台,但可以使用管道符号进行重定向:

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 streams on Wikipedia.

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

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 subprocess module 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 lassevk suggested 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 sys module. You might also want to take a look at the pipes module.

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 polling which unfortunately does not work in windows, but I'm sure there's some alternative out there.

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

#2


4  

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" Statement document.

答案是“是”,我个人喜欢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:

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

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.stderr to the same or another file. Also see this answer to a related question.

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

#3


3  

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)
  • 什么都没有去stdout(打印通常打印到)

  • the first string that gets written to stderr is the one starting with 'It'
  • 写入stderr的第一个字符串是以'It'开头的字符串

  • the next two lines are the ones that were collected in the StringIO object
  • 接下来的两行是在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,请告诉我!

#4


1  

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

你想要子进程。请参阅17.1.1中的Popen并在17.1.2中进行通信。

#5


0  

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或类似程序,并希望等到脚本/程序完成并捕获其所有输出,那么您需要查看库你用来启动那个外部程序的调用,很可能有一种方法可以让它给你一些方法来读取输出并等待完成。