2 votes

Module de sous-processus Python : la communication parent-enfant ne fonctionne pas

J'essaie d'exécuter le code suivant en tant que sous-processus

#include<stdio.h>
int main()
{
    int a;
    printf("Hello\n");
    fprintf(stderr, "Hey\n");
    scanf("%d", &a);
    printf("%d\n", a);
    return 0;
}

Ce script fonctionne correctement : écriture sur stdin, lecture sur stdout et sur stderr.

#!/usr/bin/python

import subprocess

p1=subprocess.Popen("/mnt/test/a.out", stdout=subprocess.PIPE, stdin=subprocess.PIPE, stderr=subprocess.PIPE)

p1.stdin.write('1\n')
print p1.stdout.readline()
print p1.stderr.readline()
print p1.stdout.readline()

Mais ce script ne parvient pas à lire la sortie stdout et reste bloqué à cet endroit, même si le programme C imprime sur la sortie stdout avant de demander une quelconque entrée. Comment se fait-il que je ne parvienne pas à lire quoi que ce soit sur stdout ?

#!/usr/bin/python

import subprocess

p1=subprocess.Popen("/mnt/test/a.out", stdout=subprocess.PIPE, stdin=subprocess.PIPE, stderr=subprocess.PIPE)

print p1.stdout.readline()
p1.stdin.write('1\n')
print p1.stderr.readline()
print p1.stdout.readline()

2voto

phant0m Points 8545

Vous devez affleurer le flux en premier. Cela permet de s'assurer que toutes les données sont effectivement écrites dans le flux.

#include<stdio.h>
int main()
{
    int a;
    printf("Hello\n");
    fprintf(stderr, "Hey\n");
    fflush(stdout); // <--
    scanf("%d", &a);
    printf("%d\n", a);
    return 0;
}

Par défaut, stderr n'est pas tamponné, c'est pourquoi vous n'avez pas besoin de le nettoyer. sortie standard est toutefois entièrement mis en mémoire tampon, à moins qu'il ne pointe vers un terminal, auquel cas il est mis en mémoire tampon (c'est-à-dire que l'élément \n déclencherait automatiquement la vidange.

Voir le site aquí pour setbuf() et setvbuf().

0voto

Fredrik Pihl Points 20944

Je ne vois pas quelque chose comme

stdout_data, stderr_data = p1.communicate()

dans votre code

Popen.communicate(input=None)

Interagir avec le processus : Envoyer des données à stdin. Lire les données de stdout et stderr, jusqu'à ce que la fin du fichier soit atteinte. Attendre la fin du processus. L'argument facultatif input doit être une chaîne de caractères à envoyer au processus fils, ou None, si aucune donnée ne doit être envoyée au processus fils.

communicate() renvoie un tuple (stdoutdata, stderrdata).

Notez que si vous voulez envoyer des données au stdin du processus, vous devez créer l'objet Popen avec stdin=PIPE. De même, pour obtenir autre chose que None dans le tuple de résultat, vous devez indiquer stdout=PIPE et/ou stderr=PIPE.

Remarque Les données lues sont mises en mémoire tampon. N'utilisez donc pas cette méthode si la taille des données est importante ou illimitée.

Voir docs.python.org

Une fonction que je garde dans ma ceinture utilitaire pour envelopper l'appel d'un programme externe à l'aide d'un sous-processus est la suivante (à modifier en fonction de vos besoins) :

def __run(self, cmd):
    """wrapper, makes it easy to call an external program.
    return the result as a newline-separated list
    """

    args = shlex.split(cmd)
    try:
        p = subprocess.Popen(args, stdout=subprocess.PIPE,
                             stderr=subprocess.STDOUT)
        retdata = p.communicate()[0]
        p.wait()
    except OSError, e:
        print >>sys.stderr, "Execution failed:", e

    return (p.returncode, retdata.split('\n'))

Il suffit de placer votre commande comme vous l'écririez sur la ligne cmd dans une variable et d'appeler la fonction, par exemple :

cmd = r'git branch -r'
data = self.__run(cmd)

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