管道输出导致python程序失败

时间:2013-10-31 01:02:54

标签: python unicode terminal redirect terminal-emulator

我有以下简单程序:

# -*- coding: utf-8 -*-

GREEK = u'ΑΒΓΔ ΕΖΗΘ ΙΚΛΜ ΝΞΟΠ ΡΣΤΥ ΦΧΨΩ αβγδ εζηθ ικλμ νξοπ ρςτυ φχψω'

print GREEK

在终端上运行此命令会产生,例如:

$ python test.py
ΑΒΓΔ ΕΖΗΘ ΙΚΛΜ ΝΞΟΠ ΡΣΤΥ ΦΧΨΩ αβγδ εζηθ ικλμ νξοπ ρςτυ φχψω

但是将输出传递给另一个程序会导致错误:

$ python test.py | less

Traceback (most recent call last):
  File "test.py", line 5, in <module>
    print GREEK
UnicodeEncodeError: 'ascii' codec can't encode characters in position 0-3: ordinal not in range(128)
Traceback (most recent call last):
  File "ddd.py", line 5, in <module>
    print GREEK
UnicodeEncodeError: 'ascii' codec can't encode characters in position 0-3: ordinal not in range(128)
  • 为什么会失败?为什么重定向会影响程序的运行方式?我原以为在shell中运行的程序总是重定向:有时候是终端程序,有时是另一个程序(在这种情况下是less)。为什么“目标”程序会影响源程序的执行?
  • 如何确保程序无论是发送到终端还是发送到其他目的地,我该怎么办?

2 个答案:

答案 0 :(得分:6)

基于这个其他相关问题,我已经实现了以下解决方案,它似乎非常强大,并且不需要对我的代码库的所有打印语句进行任何更改:

# -*- coding: utf-8 -*-

import sys

def set_output_encoding(encoding='utf-8'):
    import sys
    import codecs
    '''When piping to the terminal, python knows the encoding needed, and
       sets it automatically. But when piping to another program (for example,
       | less), python can not check the output encoding. In that case, it 
       is None. What I am doing here is to catch this situation for both 
       stdout and stderr and force the encoding'''
    current = sys.stdout.encoding
    if current is None :
        sys.stdout = codecs.getwriter(encoding)(sys.stdout)
    current = sys.stderr.encoding
    if current is None :
        sys.stderr = codecs.getwriter(encoding)(sys.stderr)

GREEK = u'ΑΒΓΔ ΕΖΗΘ ΙΚΛΜ ΝΞΟΠ ΡΣΤΥ ΦΧΨΩ αβγδ εζηθ ικλμ νξοπ ρςτυ φχψω'

set_output_encoding()

print GREEK
print >> sys.stderr, GREEK

测试一下:

python ddd.py             # Do not pipe anything
python ddd.py | less      # Pipe stdout, let stderr go to the terminal
python ddd.py 2>&1 | less # Pipe both stdout and stderr to less

所有这些都产生了预期的结果:

ΑΒΓΔ ΕΖΗΘ ΙΚΛΜ ΝΞΟΠ ΡΣΤΥ ΦΧΨΩ αβγδ εζηθ ικλμ νξοπ ρςτυ φχψω
ΑΒΓΔ ΕΖΗΘ ΙΚΛΜ ΝΞΟΠ ΡΣΤΥ ΦΧΨΩ αβγδ εζηθ ικλμ νξοπ ρςτυ φχψω

答案 1 :(得分:0)

您的输出程序的编码不支持这些字符。另一种方法是始终对程序中的任何内容进行编码,并在需要时对其进行解码。

# -*- coding: utf-8 -*-

GREEK = u'ΑΒΓΔ ΕΖΗΘ ΙΚΛΜ ΝΞΟΠ ΡΣΤΥ ΦΧΨΩ αβγδ εζηθ ικλμ νξοπ ρςτυ φχψω'

print GREEK.encode('utf-8')

这样可行,但它只显示编码的字符串,而不是原始字符串,因为您的终端应用程序不使用相同的编码。