pythonスクリプトをpipeで渡すとUnicodeEncodeErrorが出る。

こんなスクリプト

# -*- coding:utf-8 -*-
print u"にほんご"

shell

直接呼び出すと大丈夫

$ python pipe_sample.py
にほんご

pipeで他のコマンドに渡すとUnicodeEncodeError

$ python pipe_sample.py | cat
Traceback (most recent call last):
  File "pipe_sample.py", line 2, in <module>
    print u"にほんご"
UnicodeEncodeError: 'ascii' codec can't encode characters in position 0-3: ordinal not in range(128)

理由

直接printを呼び出したときはterminalのlocaleなどの情報を読みだして適切なエンコーディングを認識してくれるらしい。
一方pipeを経由すると、そういう気の効いたことしてくれない。

codecs使う。

codecsでstdoutをラップしてあげるとうまくいく

# -*- coding:utf-8 -*-
import codecs
import sys
sys.stdout = codecs.getwriter("utf-8")(sys.stdout)
print u"にほんご"

今度は大丈夫

$ python pipe_sample.py | cat
にほんご