Python 2からgrepにUnicodeを含む出力をパイプするときにUnicodeエラーが発生するのはなぜですか?

Python 2からgrepにUnicodeを含む出力をパイプするときにUnicodeエラーが発生するのはなぜですか?

Unicodeコードポイントと有用な文字セットの文字名を端末(xfce4-terminal)に出力するPythonスクリプトがあります。少し大きくなり、grepを介して出力をパイプしようとしましたが、結果に驚きました。Python間違い。 grepエラーは私を驚かせません。私はgrepがUnicode入力に対して設定されていないと仮定します。

エラーの簡単な1行デモ:

python -c 'print "diameter "+ unichr(0x2300)'|grep 'd'

返品

UnicodeEncodeError: 'ascii' codec can't encode character u'\u2300' in position 9: 
ordinal not in range(128)`

私のデフォルトのPythonはPython 2(Xubuntu 18.04と多くの古いPython 2コード)です。次へ追加

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

スクリプトに違いはありません(スクリプトはすべてASCII形式なので、違いはありません)。

スクリプトをPython 3に更新し、 python3 -c 'print ("diameter "+ unichr(0x2300))'|grep 'd'正常に実行した場合。これは、明示的にpython3を呼び出してスクリプトを実行可能にするshebangも機能することを意味します。問題を解決できますが、何が起こっているのか疑問に思います。

Python 2はターミナルに直接出力するのではなく、grepで出力をパイプし、別の方法で実行されることをどうやってなぜ知ることができますか?

答え1

プログラムが標準出力が端末または他のデバイスに接続されているかどうかを検出することは珍しくありません。機能isatty() posixの一部ですそしてかなり使いました。

非常に一般的な例は、次の2つのコマンド間の出力がかなり異なります。

ls
ls | cat

python2の場合は、Pythonで使用されるデフォルトのエンコーディングに変更されたようです。 https://stackoverflow.com/questions/2276200/changing-default-encoding-of-python/7892892#7892892

これは明らかに意識的なデザイン決定ですが、その利点が何であるかは不明です。

参照回答の提案は、以下を設定することです。PYTHONIOENCODING


Python2は価値が低下しました。。とにかくPython 3に切り替えてみてください。

これがなぜ違うのかという質問に答えることはありませんが、Googleでいくつかの簡単な検索をすると失敗した理由がわかります。 このスタックオーバーフローの回答この資料の最初の例を指します。

https://docs.python.org/2/library/functions.html#unichr

つまり、Unicode文字列をAskii文字列に追加する前にバイトに変換しないでください。

関連情報