stderr的python的默认编码?

时间:2009-03-12 04:45:52

标签: python bash shell unicode

我有一个嘈杂的python脚本,我希望通过将其stderr输出指向/ dev / null(使用bash BTW)来保持沉默。

像这样:

python -u parse.py  1> /tmp/output3.txt 2> /dev/null

但它很快就会过早退出。嗯。我无法看到追溯因为当然与stderr一起出现了。如果我不把stderr指向某个地方,它会吵闹地运行。

因此,让我们尝试将其重定向到某个地方而不是/ dev / null,并查看它的输出内容:

python -u parse.py  1> /tmp/output3.txt 2> /tmp/foo || tail /tmp/foo

Traceback (most recent call last):
  File "parse.py", line 79, in <module>
    parseit('pages-articles.xml')
  File "parse.py", line 33, in parseit
    print >>sys.stderr, "bad page title", page_title
UnicodeEncodeError: 'ascii' codec can't encode characters in position 0-1: ordinal not in range(128)

因此,正在生成的stderr包含utf8,并且由于某种原因,python在被重定向时拒绝打印非ascii,即使它被定向到/ dev / null(当然python当然不知道)

即使它包含utf8,我如何使python脚本的stderr静音?如果没有在这个脚本中重写每个打印到stderr,有没有办法做到这一点?

3 个答案:

答案 0 :(得分:5)

您可以通过将stderr绑定到自定义编写器来使其静音:

#!/usr/bin/env python
import codecs, sys

class NullWriter:
    def write(self, *args, **kwargs):
        pass

if len(sys.argv) == 2:
   if sys.argv[1] == '1':
      sys.stderr = NullWriter()
   elif sys.argv[1] == '2':
      #NOTE: sys.stderr.encoding is *read-only* 
      #      therefore the whole stderr should be replaced
      # encode all output using 'utf8'
      sys.stderr = codecs.getwriter('utf8')(sys.stderr)

print >>sys.stderr, u"\u20AC" # euro sign
print "ok"

示例:

$ python silence_stderr.py
Traceback (most recent call last):
  File "silence_stderr.py", line 11, in <module>
    print >>sys.stderr, u"\u20AC"
UnicodeEncodeError: 'ascii' codec can't encode character u'\u20ac' in position 0: ordinal not in range(128)

沉默的stderr:

$ python silence_stderr.py 1
ok

编码stderr:

$ python silence_stderr.py 2
€
ok

注意:我在emacs中有上述输出,因此可以在您可以执行的终端中模拟它:

$ python ... 2>out.txt
$ cat out.txt

注意:在Windows控制台内部(在chcp 65001之后切换到'utf-8'并使用truetype字体(Lucida Console))我得到了奇怪的结果:< / p>

C:\> python silence_stderr.py 2
Traceback (most recent call last):
  File "silence_stderr.py", line 14, in <module>
    print >>sys.stderr, u"\u20AC" # euro sign
  File "C:\pythonxy\python\lib\codecs.py", line 304, in write
    self.stream.write(data)
IOError: [Errno 13] Permission denied

如果字体不是truetype,则异常不会引发但输出错误。

Perl适用于truetype字体:

C:\> perl  -E"say qq(\x{20ac})"
Wide character in print at -e line 1.
€

重定向虽然有效:

C:\>python silence_stderr.py 2 2>tmp.log
ok
C:\>cat tmp.log
€
cat: write error: Permission denied

重新评论

来自codecs.getwriter文档:

  

查找给定的编解码器   编码并返回其StreamWriter   班级或工厂职能。提出一个   如果是编码,则LookupError   无法找到。

过于简化的观点:

class UTF8StreamWriter:
    def __init__(self, writer):
        self.writer = writer
    def write(self, s):
        self.writer.write(s.encode('utf-8'))

sys.stderr = UTF8StreamWriter(sys.stderr)

答案 1 :(得分:4)

当未重定向stderr时,它会对您的终端进行编码。当你重定向它时,这一切都会出现。您需要使用sys.stderr.isatty()来检测它是否被重定向并进行适当编码。

答案 2 :(得分:2)

您也可以将字符串编码为ASCII,替换不映射的unicode字符。那么你不必担心你有什么样的终端。

asciiTitle = page_title.encode("ascii", "backslashreplace")
print >>sys.stderr, "bad page title", asciiTitle

替换了无法用反斜杠转义编码的字符,即\xfc。还有一些其他替换选项,如下所述:

http://docs.python.org/library/stdtypes.html#str.encode