web-dev-qa-db-fra.com

vérifier la sortie de CalledProcessError

J'utilise subprocess.check_output du module de sous-processus pythons pour exécuter une commande ping. Voici comment je le fais:

output = subprocess.check_output(["ping","-c 2 -W 2","1.1.1.1")

Il soulève une exception CalledProcessError et indique que la sortie est l'un des arguments de la fonction. Quelqu'un peut-il m'aider à lire cette sortie? J'aimerais lire le résultat dans une chaîne et l'analyser. Donc, par exemple si le ping retourne 

100% de perte de paquet

J'ai besoin de capturer ça. S'il y a une autre meilleure façon..veuillez suggérer. Merci.

38
ash

Dans la liste des arguments, chaque entrée doit être indépendante. En utilisant

output = subprocess.check_output(["ping", "-c","2", "-W","2", "1.1.1.1"])

devrait résoudre votre problème.

12
phihag

Selon la documentation du module Python os , os.popen est obsolète depuis Python 2.6.

Je pense que la solution pour Python moderne consiste à utiliser check_output () à partir du module de sous-processus.

Dans la documentation Python subprocess :

subprocess.check_output (arguments, *, stdin = aucun, stderr = aucun, shell = faux, universal_newlines = faux) Exécutez la commande avec des arguments et renvoyez sa sortie sous forme de chaîne d'octets.

Si le code de retour était différent de zéro, il déclenche une CalledProcessError. L'objet CalledProcessError aura le code de retour dans l'attribut returncode et toute sortie dans l'attribut de sortie.

Si vous parcourez le code suivant dans Python 2.7 (ou version ultérieure):

import subprocess

try:
    print subprocess.check_output(["ping", "-n", "2", "-w", "2", "1.1.1.1"])
except subprocess.CalledProcessError, e:
    print "Ping stdout output:\n", e.output

Vous devriez voir une sortie qui ressemble à ceci:

Ping stdout output:

Pinging 1.1.1.1 with 32 bytes of data:
Request timed out.
Request timed out.

Ping statistics for 1.1.1.1:
Packets: Sent = 2, Received = 0, Lost = 2 (100% loss),

La chaîne e.output peut être analysée pour répondre aux besoins des OP. 

Si vous voulez le code de retour ou d'autres attributs, ils sont dans CalledProccessError comme on peut le voir en passant avec pdb

(Pdb)!dir(e)   

['__class__', '__delattr__', '__dict__', '__doc__', '__format__',
 '__getattribute__', '__getitem__', '__getslice__', '__hash__', '__init__',
 '__module__', '__new__', '__reduce__', '__reduce_ex__', '__repr__',
 '__setattr__', '__setstate__', '__sizeof__', '__str__', '__subclasshook__', 
 '__unicode__', '__weakref__', 'args', 'cmd', 'message', 'output', 'returncode']
145
krd

Si vous souhaitez obtenir stdout et stderr en arrière (y compris pour l'extraire de CalledProcessError le cas échéant), utilisez les éléments suivants:

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

Ceci est compatible Python 2 et 3.

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

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

Merci @krd, j'utilise votre processus de récupération des erreurs, mais je devais mettre à jour les instructions print et except. J'utilise Python 2.7.6 sur Linux Mint 17.2.

En outre, il était difficile de savoir d'où venait la chaîne de sortie . Ma mise à jour:

import subprocess

# Output returned in error handler
try:
    print("Ping stdout output on success:\n" + 
           subprocess.check_output(["ping", "-c", "2", "-w", "2", "1.1.1.1"]))
except subprocess.CalledProcessError as e:
    print("Ping stdout output on error:\n" + e.output)

# Output returned normally
try:
    print("Ping stdout output on success:\n" + 
           subprocess.check_output(["ping", "-c", "2", "-w", "2", "8.8.8.8"]))
except subprocess.CalledProcessError as e:
    print("Ping stdout output on error:\n" + e.output)

Je vois une sortie comme celle-ci:

Ping stdout output on error:
PING 1.1.1.1 (1.1.1.1) 56(84) bytes of data.

--- 1.1.1.1 ping statistics ---
2 packets transmitted, 0 received, 100% packet loss, time 1007ms


Ping stdout output on success:
PING 8.8.8.8 (8.8.8.8) 56(84) bytes of data.
64 bytes from 8.8.8.8: icmp_seq=1 ttl=59 time=37.8 ms
64 bytes from 8.8.8.8: icmp_seq=2 ttl=59 time=38.8 ms

--- 8.8.8.8 ping statistics ---
2 packets transmitted, 2 received, 0% packet loss, time 1001ms
rtt min/avg/max/mdev = 37.840/38.321/38.802/0.481 ms
0
AndruWitta

J'ai rencontré le même problème et j'ai constaté que la documentation avait un exemple pour ce type de scénario (où nous écrivons STDERR TO STDOUT et sortons toujours avec succès avec le code retour 0) sans provoquer/intercepter une exception.

output = subprocess.check_output("ping -c 2 -W 2 1.1.1.1; exit 0", stderr=subprocess.STDOUT, Shell=True)

Vous pouvez désormais utiliser la fonction de chaîne standard find pour vérifier la chaîne de sortie output.

0
Joseph