2016-05-16 3 views
6

subprocess.check_callを取得して、コマンドの生のバイナリ出力を得るには、どこかで正しくエンコードしていないようです。Pythonはsubprocess.check_callから生のバイナリを取得しません

詳細:

私はこのようなテキストを返すコマンドがあります。

some output text “quote” ... 

(これらの引用符はユニコードe2809dある)

は、ここで私は、コマンドを呼んでいる方法は次のとおりです。

f_output = SpooledTemporaryFile() 
subprocess.check_call(cmd, shell=True, stdout=f_output) 
f_output.seek(0) 
output = f_output.read() 

問題はこれです:

(私は 'ord'と '?'を呼ぶと63になります。) LinuxのPython 2.7です。

注:OSXで同じコードを実行すると、正しく動作します。問題は、Linuxサーバーで実行しているときです。

+0

呼び出される可能性のあるプログラムは、stdoutの内容に応じて出力を調整します。通常のファイルを開き、実際に書き込まれているバイト数を確認する方法ところで、 'SpooledTemporaryFile'は殺し過ぎです。 「スプールされた」部分は、Pythonから書かれたものに対してのみ機能します。ファイルディスクリプタを取得すると、それを通常の一時ファイルに変更しました。余分なStringIOバッファは使用されませんでした。 – tdelaney

+1

私はutf-8文字列を吐き出すあなたのプログラムが私のために働いた、素早いpythonプログラムを書いた。 – tdelaney

+0

シェルでコマンドを実行し、ファイルにリダイレクトしてみてください。 'vim'がインストールされている場合は、ファイルの16進ダンプを表示できる' xxd'も必要です。あなたのテキスト例では、utf-8の出力は次のようになります: '' '0000000:736f 6d65 206f 7574 7075 7420 7465 7874一部の出力テキスト 0000010:20e2 809c 7175 6f74 65e2 809d 202e 2e2e ...引用... .. 。 '' '左引用符は' e2 80 9c'で、右引用符は 'e2 80 9d'です。 –

答えて

1

うわー、これはこれまでに一番奇妙な問題でしたが、修正しました。

呼び出し元のプログラム(Javaプログラム)は、呼び出された場所によって異なるエンコーディングを返していました。

Dev osxマシンは、コマンドラインからLinuxサーバを細かく返します.Djangoアプリケーションから呼び出された場合、それは問題なく "?"に変わります。この問題を解決するには

私は、コマンドにこの引数を追加することになった:

-Dfile.encoding=utf-8 

I got that idea here、動作しているようです。 Javaプログラムを内部的に変更する方法もあります。

私はPythonを非難しました!皆さんは正しい考えを持っていました。

+0

あなたのロケール設定( 'locale.getpreferredencoding()')を私の答えで提案したように修正しようとしましたか(実行したいコードと同じコンテキストでチェックしてください)? – jfs

0

リダイレクト(stdout=file)はファイル記述子レベルで発生します。ファイル自体にの代わりに?が表示されていると、Pythonはファイルに書き込まれているものとは関係ありません(REPLではありません)。

それはOS X上で動作し、それがLinuxサーバ上で「動作しない」場合、考えられる理由は、環境の違いである、(原因shell=Trueに)/bin/sh、LC_ALL、LC_CTYPE、LANGのenvvarsが-pythonのをチェックして、 cmdは、環境が設定されていない場合はASCIIであるロケールエンコーディングを使用することがあります(C、POSIXロケール)。

サブプロセスから "生のバイナリ" を取得するには:

#!/usr/bin/env python 
import subprocess 

raw_binary = subprocess.check_output(['cmd', 'arg 1', 'arg 2']) 
print(repr(raw_binary)) 

注:

  • 多くのプログラムは、彼らの行動を変えることが必要な場合を除き

    • shell=Trueはそれを使用しない-don't出力がttyではないことが検出された場合はexampleです。