2016-05-16 23 views
6

Come posso ottenere subprocess.check_call per darmi l'output binario non elaborato di un comando, sembra che lo stia codificando in modo errato da qualche parte.Python non ottiene raw binary dal sottoprocesso.check_call

Dettagli:

mi hanno un comando che restituisce testo come questo:

some output text “quote” ... 

(quelle citazioni sono e2809d unicode)

Ecco come sto chiamando il comando:

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

Il problema è che ottengo questo:

>>> repr(output) 
some output text ?quote? ... 
>>> type(output) 
<str> 

(E se chiamo 'ord' il '?' Ottengo 63.) Sono su Python 2.7 su Linux.

Nota: l'esecuzione dello stesso codice su OSX funziona correttamente con me. Il problema è quando lo eseguo su un server Linux.

+0

E 'possibile che il programma chiamato modifichi l'uscita in base a quale stdout è. Che ne dici di aprire un file regolare e vedere quali byte sono effettivamente scritti. BTW, 'SpooledTemporaryFile' è sopra uccisione. La parte "spool" funziona solo per cose scritte da python. Quando hai ottenuto il descrittore del file lo ha cambiato in un normale file temporaneo. Il buffer StringIO extra non è stato utilizzato. – tdelaney

+1

Ho scritto un rapido programma python che sputa la stringa utf-8 e il tuo programma ha funzionato per me. – tdelaney

+0

Provare a eseguire il comando in una shell e reindirizzare a un file. Se hai 'vim' installato dovresti anche avere' xxd', che può visualizzare un dump esadecimale di file. Nel testo di esempio, l'output di utf-8 dovrebbe essere simile a: '' '0000000: 736f 6d65 206f 7574 7075 7420 7465 7874 parte del testo di output 0000010: 20e2 809c 7175 6f74 65e2 809d 202e 2e2e ... preventivo ... .. .''' La virgoletta di sinistra è 'e2 80 9c' e la citazione di destra è' e2 80 9d' –

risposta

1

Wow, questo è stato il problema più strano di sempre ma l'ho risolto!

Si scopre che il programma che stava chiamando (un programma java) restituiva una codifica diversa a seconda di dove era stato chiamato!

Dev osx machine, restituisce i caratteri bene, server Linux da riga di comando, li restituisce bene, chiamato da un'app Django, nope si trasforma in "?" S.

Per correggere questo ho finito per l'aggiunta di questo argomento per il comando:

-Dfile.encoding=utf-8 

I got that idea here, e sembra funzionare. C'è anche un modo per modificare internamente il programma Java per farlo.

Scusa se ho dato la colpa a Python! Ragazzi avete avuto l'idea giusta.

+0

hai provato a correggere le impostazioni locali ('locale.getpreferredencoding()') come suggerito nella mia risposta (controllale nello stesso contesto del codice che vuoi eseguire)? – jfs

0

Il reindirizzamento (stdout=file) si verifica a livello del descrittore di file. Python non ha nulla a che fare con ciò che viene scritto nel file se vedi ? invece di nel file stesso (non in un REPL).

Se funziona su OS X e "non funziona" sul server Linux, allora la ragione probabile è la differenza per l'ambiente, controllare LC_ALL, LC_CTYPE, LANG envvars-python, /bin/sh (a causa di shell=True), e il cmd può utilizzare la codifica locale ASCII se l'ambiente non è impostato (C, POSIX locale).

per ottenere "binario non elaborato" da un sottoprocesso:

#!/usr/bin/env python 
import subprocess 

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

Nota:

  • senza shell=True -Non lo usano a meno che non sia necessario
  • molti programmi possono cambiare il loro comportamento se rilevano che l'output non è un tty, example.