web-dev-qa-db-fra.com

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

Comment puis-je obtenir la sortie d'un processus exécuté en utilisant subprocess.call()?

Passer un objet StringIO.StringIO à 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'
>>> 
243
Jeffrey Aylesworth

La sortie de subprocess.call() ne devrait être redirigée que vers des fichiers.

Vous devriez utiliser subprocess.Popen() à la place. Ensuite, vous pouvez passer subprocess.PIPE pour les paramètres stderr, stdout et/ou stdin et lire à partir des canaux en utilisant la méthode communicate():

from subprocess import Popen, PIPE

p = Popen(['program', 'arg1'], stdin=PIPE, stdout=PIPE, stderr=PIPE)
output, err = p.communicate(b"input data that is passed to subprocess' stdin")
rc = p.returncode

Le raisonnement est que l'objet de type fichier utilisé par subprocess.call() doit avoir un descripteur de fichier réel et implémenter ainsi la méthode fileno(). Utiliser n'importe quel objet de type fichier ne fera pas l'affaire.

Voir ici pour plus d'informations.

190
Mike

Si vous avez Python version> = 2.7, vous pouvez utiliser subprocess.check_output qui fait exactement ce que vous voulez (il renvoie la sortie standard sous forme de chaîne).

Exemple simple (version linux, voir note):

import subprocess

print subprocess.check_output(["ping", "-c", "1", "8.8.8.8"])

Notez que la commande ping utilise la notation linux (-c pour count). Si vous essayez ceci sous Windows, n'oubliez pas de le changer en -n pour le même résultat.

Comme indiqué ci-dessous, vous trouverez une explication plus détaillée dans cette autre réponse .

243
sargue

J'ai la solution suivante. Il capture le code de sortie, le stdout et le stderr de la commande externe exécutée:

import shlex
from subprocess import Popen, PIPE

def get_exitcode_stdout_stderr(cmd):
    """
    Execute the external command and get its exitcode, stdout and stderr.
    """
    args = shlex.split(cmd)

    proc = Popen(args, stdout=PIPE, stderr=PIPE)
    out, err = proc.communicate()
    exitcode = proc.returncode
    #
    return exitcode, out, err

cmd = "..."  # arbitrary external command, e.g. "python mytest.py"
exitcode, out, err = get_exitcode_stdout_stderr(cmd)

J'ai aussi un article de blog dessus ici .

Modifiez: la solution a été mise à jour pour une solution plus récente ne nécessitant pas d'écriture sur temp. des dossiers.

47
Jabba

Pour python 3.5+, il est recommandé d'utiliser la fonction fonction d'exécution à partir du module de sous-processus . Cela renvoie un objet CompletedProcess, à partir duquel vous pouvez facilement obtenir le résultat ainsi que le code de retour.

from subprocess import PIPE, run

command = ['echo', 'hello']
result = run(command, stdout=PIPE, stderr=PIPE, universal_newlines=True)
print(result.returncode, result.stdout, result.stderr)
43
Chiel ten Brinke

J'ai récemment découvert comment faire cela, et voici quelques exemples de code d'un de mes projets en cours:

#Getting the random picture.
#First find all pictures:
import shlex, subprocess
cmd = 'find ../Pictures/ -regex ".*\(JPG\|NEF\|jpg\)" '
#cmd = raw_input("Shell:")
args = shlex.split(cmd)
output,error = subprocess.Popen(args,stdout = subprocess.PIPE, stderr= subprocess.PIPE).communicate()
#Another way to get output
#output = subprocess.Popen(args,stdout = subprocess.PIPE).stdout
ber = raw_input("search complete, display results?")
print output
#... and on to the selection process ...

Vous avez maintenant la sortie de la commande stockée dans la variable "sortie". "stdout = subprocess.PIPE" indique à la classe de créer un objet fichier nommé "stdout" à partir de Popen. D'après ce que je peux dire, la méthode communique () constitue simplement un moyen pratique de renvoyer un tuple de la sortie et des erreurs du processus que vous avez exécuté. En outre, le processus est exécuté lors de l'instanciation de Popen.

28
Cheesemold

Dans Ipython Shell:

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 à la sargue.

14
jhegedus

Ce qui suit capture stdout et stderr du processus dans une seule variable. Il est compatible Python 2 et 3:

from subprocess import check_output, CalledProcessError, STDOUT

command = ["ls", "-l"]
try:
    output = check_output(command, stderr=STDOUT).decode()
    success = True 
except CalledProcessError as e:
    output = e.output.decode()
    success = False

Si votre commande est une chaîne plutôt qu'un tableau, préfixez ceci avec:

import shlex
command = shlex.split(command)
11
Zags