333 votes

Récupération de la sortie de subprocess.call()

Comment puis-je obtenir la sortie d'un processus exécuté à l'aide de subprocess.call() ?

Passage d'un StringIO.StringIO à l'objet stdout donne cette erreur :

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/Library/Frameworks/Python.framework/Versions/2.6/lib/python2.6/subprocess.py", line 444, in call
    return Popen(*popenargs, **kwargs).wait()
  File "/Library/Frameworks/Python.framework/Versions/2.6/lib/python2.6/subprocess.py", line 588, in __init__
    errread, errwrite) = self._get_handles(stdin, stdout, stderr)
  File "/Library/Frameworks/Python.framework/Versions/2.6/lib/python2.6/subprocess.py", line 945, in _get_handles
    c2pwrite = stdout.fileno()
AttributeError: StringIO instance has no attribute 'fileno'
>>>

2 votes

La réponse de Mike est correcte. Notez que StringIO fonctionne comme un fichier dans la plupart des cas mais pas tous. Cela ne fonctionne pas dans votre cas parce que la multiprocessing suppose des fichiers réels dans certains cas. Ceci a peut-être été corrigé : voir bugs.python.org/issue5313 pour un bogue connexe.

0 votes

En fait, communicate() utilise select.select() qui n'accepte que les descripteurs de fichiers, ce n'est donc pas vraiment un bogue. J'étais assez confus par ce problème lorsque je l'ai rencontré pour la première fois et l'exploration des profondeurs de subprocess.py m'a beaucoup appris !

1 votes

Je pense subprocess.run rend cela plus simple, à partir de Python 3.5. J'ajouterai une réponse quand j'en aurai l'occasion.

29voto

Zags Points 582

La clé est d'utiliser la fonction subprocess.check_coutput

Par exemple, la fonction suivante capture stdout et stderr du processus et les renvoie ainsi que le fait que l'appel ait réussi ou non. Elle est compatible avec Python 2 et 3 :

from subprocess import check_output, CalledProcessError, STDOUT

def system_call(command):
    """ 
    params:
        command: list of strings, ex. `["ls", "-l"]`
    returns: output, success
    """
    try:
        output = check_output(command, stderr=STDOUT).decode()
        success = True 
    except CalledProcessError as e:
        output = e.output.decode()
        success = False
    return output, success

output, success = system_call(["ls", "-l"])

Si vous souhaitez passer des commandes sous forme de chaînes plutôt que de tableaux, utilisez cette version :

from subprocess import check_output, CalledProcessError, STDOUT
import shlex

def system_call(command):
    """ 
    params:
        command: string, ex. `"ls -l"`
    returns: output, success
    """
    command = shlex.split(command)
    try:
        output = check_output(command, stderr=STDOUT).decode()
        success = True 
    except CalledProcessError as e:
        output = e.output.decode()
        success = False
    return output, success

output, success = system_call("ls -l")

0 votes

Np, c'était facile à rechercher. BTW, il a également un input= pour spécifier l'entrée à injecter dans la commande au lieu de la méthode super-compliquée de l'option Popen .

0 votes

Génial car il fonctionne même avec un code de sortie non nul !

0 votes

Une façon absolument géniale de le faire, exactement ce que je cherchais. Et pour clarifier le commentaire de Jason : avec un code de sortie non nul, vous arriverez à la partie du gestionnaire d'exception, donc votre success sera False

16voto

jhegedus Points 1314

Sur Ipython coquille :

In [8]: import subprocess
In [9]: s=subprocess.check_output(["echo", "Hello World!"])
In [10]: s
Out[10]: 'Hello World!\n'

Basé sur la réponse de sargue. Crédit à sargue.

1 votes

s=subprocess.check_output(["echo", "Hello World!"]); print(s) imprime comme b'Hello World!\n' comment pourrais-je me débarrasser de b'' index ? @jhegedus

1 votes

Try b "Hello World ! \n '.decode("utf-8")

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X