Piping output causes python program to fail
本问题已经有最佳答案,请猛点这里访问。
我有以下简单程序:
1 2 3 4 5 | # -*- coding: utf-8 -*- GREEK = u'ΑΒΓΔ ΕΖΗΘ ΙΚΛΜ ΝΞΟΠ ΡΣΤΥ ΦΧΨΩ αβγδ εζηθ ικλμ νξοπ ρ?τυ φχψω' print GREEK |
在终端上运行此命令会产生预期的结果:
1 2 | $ python test.py ΑΒΓΔ ΕΖΗΘ ΙΚΛΜ ΝΞΟΠ ΡΣΤΥ ΦΧΨΩ αβγδ εζηθ ικλμ νξοπ ρ?τυ φχψω |
但是通过管道将输出传输到另一个程序会导致错误:
1 2 3 4 5 6 7 8 9 10 | $ 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 )。为什么"目的地"程序会影响源程序的执行? - 我能做些什么来确保程序独立运行,不管它是发送到终端还是另一个目的地?
基于这一点以及其他相关问题,我已经实现了以下解决方案,它看起来非常健壮,不需要对代码库的所有打印语句进行任何更改:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | # -*- 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 |
测试:
1 2 3 | 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 2 | ΑΒΓΔ ΕΖΗΘ ΙΚΛΜ ΝΞΟΠ ΡΣΤΥ ΦΧΨΩ αβγδ εζηθ ικλμ νξοπ ρ?τυ φχψω ΑΒΓΔ ΕΖΗΘ ΙΚΛΜ ΝΞΟΠ ΡΣΤΥ ΦΧΨΩ αβγδ εζηθ ικλμ νξοπ ρ?τυ φχψω |
输出程序的编码不支持字符。另一种方法是始终对程序中的任何内容进行编码,并在需要时将其解码回来。
1 2 3 4 5 | # -*- coding: utf-8 -*- GREEK = u'ΑΒΓΔ ΕΖΗΘ ΙΚΛΜ ΝΞΟΠ ΡΣΤΥ ΦΧΨΩ αβγδ εζηθ ικλμ νξοπ ρ?τυ φχψω' print GREEK.encode('utf-8') |
不过,这是可行的,因为您的终端应用程序不使用相同的编码,所以它只显示已编码的字符串,而不是原始字符串。