Python重定向标准输入、标准输出和标准错误

UNIX用户已经对标准输入、标准输出和标准错误的概念熟悉了。这一节是为其它不熟悉的人准备的。

标准输出和标准错误(通常缩写为 stdout 和 stderr)是建立在每个UNIX系统内的管道(pipe)。当你 print 某东西时,结果输出到 stdout 管道中;当你的程序崩溃并打印出调试信息时(象Python中的错误跟踪),结果输出到 stderr 管道中。通常这两个管道只与你正在工作的终端窗口相联,所以当一个程序打印输出时,你可以看到输出,并且当一个程序崩溃时,你可以看到调试信息。(如果你在一个基于窗口的Python IDE系统上工作,stdout 和 stderr 缺省为“交互窗口”。)

例 5.32. stdout 和 stderr 介绍

>>> for i in range(3):
...     print 'Dive in'             1
Dive in
Dive in
Dive in
>>> import sys
>>> for i in range(3):
...     sys.stdout.write('Dive in') 2
Dive inDive inDive in
>>> for i in range(3):
...     sys.stderr.write('Dive in') 3
Dive inDive inDive in
1

正如我们在例 3.28中看到的,我们可以使用Python内置的 range 函数来创建简单的计数循环,即重复某物一定的次数。

2

stdout 是一个类文件对象;调用它的 write 函数会打印出任何给出的字符串。事实上,这就是 print 函数真正所做的;它会在正打印的字符串后面加上回车换行符,并调用sys.stdout.write

3

在最简单的例子中,stdout 和 stderr 将它们的输出发送到同一个地方:Python IDE,或终端(如果你正从命令行运行Python)。象 stdoutstderr 并不为你增加回车换行符;如果需要,要自已加上。

stdout 和 stderr 都是类文件对象,就象我们在提取输入源中所讨论的一样,但它们都是只写的。它们没有 read 方法,只有 write。然而,它们的确是类文件对象,并且你可以将任意文件对象或类文件对象赋给它们来重定向输出。

例 5.33. 重定向输出

[f8dy@oliver kgp]$ python2 stdout.py
Dive in
[f8dy@oliver kgp]$ cat out.log
This message will be logged instead of displayed

如果你还没有这样做,你可以下载本书中用到的本例和其它例子

#stdout.py
import sys

print 'Dive in'                                          1
saveout = sys.stdout                                     2
fsock = open('out.log', 'w')                             3
sys.stdout = fsock                                       4
print 'This message will be logged instead of displayed' 5
sys.stdout = saveout                                     6
fsock.close()                                            7
1

这样会打印到IDE的“交互窗口”中(或终端,如果你从命令行运行这一脚本)。

2

始终在重定向 stdout 之前保存它,这样你可以在后面将其设回正常。

3打开一个新文件用于写入。
4

将所有后续的输出重定向到我们刚打开的新文件上。

5

这样只会将输出结果“打印”到日志文件中;在IDE窗口中或在屏幕上不会看到输出结果。

6

在我们将 stdout 搞乱之前,让我们把它设回原来的方式。

7关闭日志文件。

重定向 stderr 完全以相同的方式进行,用 sys.stderr 代替 sys.stdout

例 5.34. 重定向错误信息

[f8dy@oliver kgp]$ python2 stderr.py
[f8dy@oliver kgp]$ cat error.log
Traceback (most recent line last):
  File "stderr.py", line 5, in ?
    raise Exception, 'this error will be logged'
Exception: this error will be logged

如果你还没有这样做,你可以下载本书中用到的本例和其它例子

#stderr.py
import sys

fsock = open('error.log', 'w')               1
sys.stderr = fsock                           2
raise Exception, 'this error will be logged' 3 4
1

打开我们想用来存储调试信息的日志文件。

2

将我们新打开的日志文件的文件对象赋给 stderr 重定向标准错误。

3

引发一个异常。从屏幕输出上我们可以注意到这样没有在屏幕上打印出任何东西。所以正常跟踪信息已经写进 error.log

4

还要注意我们既没有显示地关闭日志文件,也没有将 stderr 设回它的初始值。这样挺好,因为一旦程序崩溃(由于我们的异常),Python将替我们清理和关闭文件,并且 stderr 永远不恢复不会造成什么不同。因为,我提到过,一旦程序崩溃,则Python也结束。如果你希望在同一个脚本的后面去做其它的事情,恢复初始值对 stdout 更为重要。

另一方面,标准输入是只读文件对象,同时它表示从前面某个程序的数据流入这个程序。这一点可能对典型的Mac OS用户可能没什么意义,或者甚至是对Windows用户也是如此,除非你更习惯在MS-DOS命令行下工作。它的工作方式是:你可以在单个文件中构造一个命令行的链,这样一个程序的输出成为链中下一个程序的输入。第一个程序简单地输出到标准输出(本身不需要任何特别的重定义,只是执行正常的 print 什么的),同时下个程序从标准输入读入,操作系统会小心地将一个程序的输出连接到下一个程序的输入。

例 5.35. 链接命令

[f8dy@oliver kgp]$ python2 kgp.py -g binary.xml         1
01100111
[f8dy@oliver kgp]$ cat binary.xml                       2
<?xml version="1.0"?>
<!DOCTYPE grammar PUBLIC "-//diveintopython.org//DTD Kant Generator Pro v1.0//EN" "kgp.dtd">
<grammar>
<ref id="bit">
  <p>0</p>
  <p>1</p>
</ref>
<ref id="byte">
  <p><xref id="bit"/><xref id="bit"/><xref id="bit"/><xref id="bit"/>\
<xref id="bit"/><xref id="bit"/><xref id="bit"/><xref id="bit"/></p>
</ref>
</grammar>
[f8dy@oliver kgp]$ cat binary.xml | python2 kgp.py -g - 3 4
10110001
1

正如我们在接触中看到的,这样会打印出8个随机比特(0 或 1)的字符串。

2

这样会简单地打印出 binary.xml 的全部内容。(Windows用户应该使用 type 代替 cat。)

3

这样会打印 binary.xml 的内容,但是“|”字符,叫做管道符,表示输出内容不会打印到屏幕上。相反,它们成为下个命令(在本例中调用我们的Python脚本)的标准输入。

4

我们没有指定一个模块(象 binary.xml),而是指定“-”,这会让我们的脚本从标准输入而不是从磁盘上的一个特别文件中装入语法。(在下个例子中有更多关于它是如何发生的内容。)这样效果同第一个语法(我们直接指定语法文件名)是一样的,但它考虑了这里的扩展的可能性。不只是简单地执行 cat binary.xml,我们可以运行一个可以动态生成语法的脚本,然后可以将它通过管道输入到我们的脚本中。语法可以来自任何地方:数据库,或某个语法生成元脚本什么的。要点就是我们完全不必修改我们的 kgp.py 脚本就可以同任何这种功能进行合并。我们要做的只是能够从标准输入中接收语法文件,并且我们可以将所有其它的逻辑分散到另一个程序中。

那么当语法文件是“-”时我们的脚本是如何中从标准输入读入的呢?没什么神秘的,就是编码。

例 5.36. 在 kgp.py 中从标准输入读入

def openAnything(source):
    if source == "-":    1
        import sys
        return sys.stdin

    # try to open with urllib (if source is http, ftp, or file URL)
    import urllib
    try:

[... 略 ...]
1

这是来自 toolbox.py 中的 openAnything 函数,我们在提取输入源中讨论过的。我们所做的全部是在函数的开始处添加三行代码,用来检查是否 source 是“-”,如果是,我们返回sys.stdin。实际上,就是这样!记住,stdin 是一个带有 read 方法的类文件对象,所以我们代码的其余部分(在 kgp.py 中,我们调用 openAnything 的地方)一点没有改变。

忽略输入重定向错误标准输出端是指在编程中,当尝试从标准输入(stdin)获取数据但实际没有数据或者读取操作出错时,通常会遇到`Broken pipe`这样的错误。在某些情况下,我们可能希望程序能够继续执行而不会因为这类错误就终止,这时可以采取以下策略: 1. **使用异常处理**:在试图读取输入时,捕获可能出现的`IOError`或`EOFError`(End Of File)异常,并在捕获到异常后选择性地忽视或者记录错误信息,而不是让程序立即退出。 ```python try: data = input() # 或者 sys.stdin.readline() except (IOError, EOFError): print("Input error, but continuing...") # 然后处理data变量,如果为空则忽略或默认值处理 ``` 2. **使用空值检查**:检查输入是否为空,而非依赖于具体的错误处理。例如,在读取一行时,如果没有内容,可以直接跳过或设置默认值。 ```python data = input() if not data: data = "default_value" ``` 3. **设置非阻塞模式**:在一些系统调用中,可以设置输入流为非阻塞模式,使得程序在等待输入时不会一直挂起,而是返回一个标志表示没有新的输入。 ```bash command < /dev/null &>/dev/null & ``` 在上述命令中,`<&-`关闭标准输入,`>&-`关闭标准输出,使其不再重定向输入,即使无输入也不会阻塞。 请注意,具体情况取决于你的程序需求和所使用的编程语言环境。在大多数情况下,直接处理这类错误或提供合理默认值更为妥当。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值