web-dev-qa-db-fra.com

Comment exécuter un sous-processus avec Python, attendre qu'il se termine et obtenir la sortie standard complète sous forme de chaîne?

J'ai donc remarqué subprocess.call en attendant que la commande se termine avant de poursuivre avec le script python, je n'ai aucun moyen d'obtenir la sortie standard, sauf avec subprocess.Popen. Existe-t-il des appels de fonction alternatifs qui attendraient la fin? (J'ai aussi essayé Popen.wait)

REMARQUE: j'essaie d'éviter os.system appel

result = subprocess.Popen([commands...,
                        self.tmpfile.path()], stdout=subprocess.PIPE, stderr=subprocess.PIPE)
out, err = result.communicate()
print out+"HIHIHI"

ma sortie:

HIHIHI

REMARQUE: j'essaie d'exécuter wine avec cela.

28
Stupid.Fat.Cat

J'utilise la construction suivante, bien que vous souhaitiez peut-être éviter Shell=True. Cela vous donne la sortie et le message d'erreur pour toute commande, ainsi que le code d'erreur:

process = subprocess.Popen(cmd, Shell=True,
                           stdout=subprocess.PIPE, 
                           stderr=subprocess.PIPE)

# wait for the process to terminate
out, err = process.communicate()
errcode = process.returncode
70
Alex
subprocess.check_output(...)

appelle le processus, déclenche si son code d'erreur est différent de zéro et renvoie sinon sa sortie standard. C'est juste un raccourci rapide pour que vous n'ayez pas à vous soucier des PIPE et des choses.

19
Katriel

Si votre processus donne un stdout énorme et pas de stderr, communicate() pourrait être la mauvaise façon de procéder en raison de restrictions de mémoire.

Au lieu,

process = subprocess.Popen(cmd, Shell=True,
                           stdout=subprocess.PIPE, 
                           stderr=subprocess.PIPE)

# wait for the process to terminate
for line in process.stdout: do_something(line)
errcode = process.returncode

pourrait être la voie à suivre.

process.stdout Est un objet de type fichier que vous pouvez traiter comme tout autre objet de ce type, principalement:

  • vous pouvez read() à partir de celui-ci
  • vous pouvez readline() et
  • vous pouvez le parcourir.

Ce dernier est ce que je fais ci-dessus afin d'obtenir son contenu ligne par ligne.

13
glglgl

J'essaierais quelque chose comme:

#!/usr/bin/python
from __future__ import print_function

import shlex
from subprocess import Popen, PIPE

def shlep(cmd):
    '''shlex split and popen
    '''
    parsed_cmd = shlex.split(cmd)
    ## if parsed_cmd[0] not in approved_commands:
    ##    raise ValueError, "Bad User!  No output for you!"
    proc = Popen(parsed_command, stdout=PIPE, stderr=PIPE)
    out, err = proc.communicate()
    return (proc.returncode, out, err)

... En d'autres termes, laissez shlex.split () faire la plupart du travail. Je n'essaierais PAS d'analyser la ligne de commande de Shell, de trouver des opérateurs de tuyaux et de configurer votre propre pipeline. Si vous allez faire cela, vous devrez essentiellement écrire un analyseur syntaxique complet de Shell et vous finirez par faire beaucoup de plomberie.

Bien sûr, cela soulève la question, pourquoi ne pas simplement utiliser Popen avec l'option Shell = True (mot-clé)? Cela vous permettra de passer une chaîne (pas de fractionnement ni d'analyse) au shell et de rassembler les résultats à gérer comme vous le souhaitez. Mon exemple ici ne traitera pas les pipelines, les raccourcis, la redirection des descripteurs de fichiers, etc. qui pourraient être dans la commande, ils apparaîtront tous comme des arguments littéraux à la commande. Ainsi, il est toujours plus sûr de s'exécuter avec Shell = True ... J'ai donné un exemple stupide de vérification de la commande par rapport à une sorte de dictionnaire de "commande approuvée" ou de définition --- à travers elle, cela ferait plus de sens pour normaliser cela dans un chemin absolu, sauf si vous avez l'intention d'exiger que les arguments soient normalisés avant de passer la chaîne de commande à cette fonction.

1
Jim Dennis