10

这是here的一个后续问题,具体涉及其答案


从 python 模块中,我调用了一个简单地打印到标准输出的Hello World可执行文件。Hello World我有兴趣将该输出重定向到 pythonStringIO并遇到这个答案,这几乎把我带到了解决方案。

这个答案的关键部分是这个代码段:

1. def redirect_stdout():
2.     print "Redirecting stdout"
3.     sys.stdout.flush() # <--- important when redirecting to files
4.     newstdout = os.dup(1)
5.     devnull = os.open('/dev/null', os.O_WRONLY)
6.     os.dup2(devnull, 1)
7.     os.close(devnull)
8.     sys.stdout = os.fdopen(newstdout, 'w')

我也想恢复重定向之前的标准输出。

问题

  1. 上面的函数到底发生了什么?
    • 什么是dupdup2做什么?
    • 是什么/dev/null
    • 8号线在做什么?( sys.stdout = os.fdopen(newstdout, 'w'))
  2. 如何将标准输出存储在StringIO对象中?
  3. 调用Hello World程序后如何恢复标准输出?

我很确定,一旦我得到问题 1 的答案,问题 2 和 3 的答案就会很容易。无论如何,我决定发布它们,以便将问题 1 的答案推向我想去的方向。

4

3 回答 3

13

我在下面写了一些额外的评论,这些评论应该更清楚地说明redirect_stdout函数内部发生了什么:

def redirect_stdout():
    print "Redirecting stdout"
    sys.stdout.flush() # <--- important when redirecting to files

    # Duplicate stdout (file descriptor 1)
    # to a different file descriptor number
    newstdout = os.dup(1)

    # /dev/null is used just to discard what is being printed
    devnull = os.open('/dev/null', os.O_WRONLY)

    # Duplicate the file descriptor for /dev/null
    # and overwrite the value for stdout (file descriptor 1)
    os.dup2(devnull, 1)

    # Close devnull after duplication (no longer needed)
    os.close(devnull)

    # Use the original stdout to still be able
    # to print to stdout within python
    sys.stdout = os.fdopen(newstdout, 'w')

需要注意的重要一点是,一个进程在启动时会从操作系统获取三个不同的文件描述符:

  • 标准输入:0
  • 标准输出:1
  • 标准错误:2

正如评论中所解释的,上面的代码利用了标准输出的文件描述符和文件描述符复制函数来欺骗 C 代码使用不同的标准输出,同时仍然保持对 python 代码中原始标准输出的引用能够打印。

于 2012-01-10T14:47:26.547 回答
7

/dev/null是一个特殊的设备文件(UNIX 中的一切都是文件!),它像黑洞一样吞噬写入它的所有内容。dup复制一个文件描述符。如果您习惯于 Windows,则 UNIX 中的文件描述符是一个特殊的整数,它表示一个打开的文件,它就像一个 Windows 文件句柄。

该程序正在打开/dev/null(仅)写入,获取文件描述符的副本,关闭打开的文件(因为拥有文件描述符足以让 UNIX 写入文件,您不需要保持资源打开),然后将打开的文件分配给sys.stdout.

请记住sys,Python 模块代表各种特定于系统的资源,例如文件系统。因此,在 UNIXsys.stdout中将代表/dev/stdoutie 系统STDOUT流。

所以,总而言之,这段代码让 Python 误以为/dev/null/现在STDOUT每次你的程序STDOUTprint语句(Python3 中的函数)写入时,它就会真正写入,/dev/null而你永远不会在控制台上看到结果文本.

于 2012-01-10T14:46:31.150 回答
-1

请参阅作为这些 Python 函数基础的 C 运行时函数的手册页。

基本上,它们将文件描述符复制到新的文件描述符(使用dup())或调用中指定的文件描述符中,使用dup2().

于 2012-01-10T14:40:11.593 回答