1332 votes

Exécution de la commande shell à partir de python et capture de la sortie

Je veux écrire une fonction qui va exécuter une commande shell et retourner sa sortie sous forme de chaîne , peu importe, est-ce un message d'erreur ou de succès. Je veux juste obtenir le même résultat que j'aurais obtenu avec la ligne de commande.

Quelqu'un peut-il donner un exemple de code qui ferait une telle chose?

Par exemple:

 def run_command(cmd):
    # ??????

print run_command('mysqladmin create test -uroot -pmysqladmin12')
# should output something like:
# mysqladmin: CREATE DATABASE failed; error: 'Can't create database 'test'; database exists'
 

1781voto

senderle Points 41607

Pour plus de commodité, Python 2.7 fournit l'

subprocess.check_output(*popenargs, **kwargs)  

la fonction, qui prend les mêmes arguments que Popen, mais renvoie une chaîne contenant le programme de la sortie. Vous pouvez transmettre stderr=subprocess.STDOUT afin d'assurer que les messages d'erreur sont inclus dans les résultats retournés -- mais ne passe pas stderr=subprocess.PIPE, ce qui peut provoquer des blocages. Voir ici pour plus d'.

Si vous utilisez une ancienne python, Vartec de la méthode de travail. Mais la meilleure façon d'aller-au moins dans les cas les plus simples qui ne nécessitent pas une sortie en temps réel de capture, est d'utiliser communicate. Comme dans:

output = Popen(["mycmd", "myarg"], stdout=PIPE).communicate()[0]

Ou

>>> import subprocess
>>> p = subprocess.Popen(['ls', '-a'], stdout=subprocess.PIPE, 
...                                    stderr=subprocess.PIPE)
>>> out, err = p.communicate()
>>> print out
.
..
foo

Si vous définissez stdin=PIPE, communicate vous permet aussi de passer des données à traiter par le biais d' stdin:

>>> cmd = ['awk', 'length($0) > 5']
>>> p = subprocess.Popen(cmd, stdout=subprocess.PIPE,
...                           stderr=subprocess.PIPE,
...                           stdin=subprocess.PIPE)
>>> out, err = p.communicate('foo\nfoofoo\n')
>>> print out
foofoo

Enfin, notez Aaron Hall de réponse, ce qui indique que sur certains systèmes, vous devez configurer stdout, stderr, et stdin tous PIPE (ou DEVNULL) pour obtenir de l' communicate à travailler à tous.

202voto

byte_array Points 594

C'est beaucoup plus facile, mais ne fonctionne que sur Unix.

 import commands
print commands.getstatusoutput('wc -l file')
 

126voto

vartec Points 53382

Quelque chose comme ca:

 def runProcess(exe):    
    p = subprocess.Popen(exe, stdout=subprocess.PIPE, stderr=subprocess.STDOUT)
    while(True):
      retcode = p.poll() #returns None while subprocess is running
      line = p.stdout.readline()
      yield line
      if(retcode is not None):
        break
 

Notez que je redirige stderr vers stdout, ce n'est peut-être pas exactement ce que vous voulez, mais je veux aussi des messages d'erreur.

Cette fonction donne ligne par ligne au fur et à mesure (normalement, il faut attendre que le sous-processus se termine pour obtenir la sortie dans son ensemble.

Pour votre cas, l'utilisation serait:

 for line in runProcess('mysqladmin create test -uroot -pmysqladmin12'.split()):
    print line,
 

77voto

Max Persson Points 221

La réponse de Vartec ne lit pas toutes les lignes, donc j'ai fait une version qui a fait:

 def run_command(command):
    p = subprocess.Popen(command,
                         stdout=subprocess.PIPE,
                         stderr=subprocess.STDOUT)
    return iter(p.stdout.readline, b'')
 

L'utilisation est la même que la réponse acceptée:

 command = 'mysqladmin create test -uroot -pmysqladmin12'
for line in run_command(command):
    print(line)
 

12voto

Aaron Hall Points 7381

Votre Kilométrage Peut Varier, j'ai tenté @senderle du spin sur Vartec une solution de Windows sur Python 2.6.5, mais j'ai été faire des erreurs, et pas d'autres solutions travaillé. Mon erreur était: WindowsError: [Error 6] The handle is invalid.

J'ai trouvé que je devais attribuer PIPE à chaque gérer pour obtenir un retour de la sortie que j'attendais la suite travaillé pour moi.

import subprocess

def run_command(cmd):
    '''given shell command, returns communication tuple of stdout and stderr'''
    return subprocess.Popen(cmd, 
                            stdout=subprocess.PIPE, 
                            stderr=subprocess.PIPE, 
                            stdin=subprocess.PIPE).communicate()

et de les appeler comme cela, ([0] obtient le premier élément du tuple, stdout):

run_command('tracert 11.1.0.1')[0]

Après en avoir appris plus, je crois que j'ai besoin de ces tuyaux arguments parce que je suis en train de travailler sur un système personnalisé qui utilise différentes poignées, j'ai donc directement le contrôle de toutes les mst.

Pour arrêter la console de popups (avec Windows), faites ceci:

def run_command(cmd):
    '''given shell command, returns communication tuple of stdout and stderr'''
    # instantiate a startupinfo obj:
    startupinfo = subprocess.STARTUPINFO()
    # set the use show window flag, might make conditional on being in Windows:
    startupinfo.dwFlags |= subprocess.STARTF_USESHOWWINDOW
    # pass as the startupinfo keyword argument:
    subprocess.Popen('tracert 11.1.0.1', 
                     stdout=subprocess.PIPE, 
                     stderr=subprocess.PIPE, 
                     stdin=subprocess.PIPE, 
                     startupinfo=startupinfo).communicate()

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