Модуль подпроцесса Python: связь родитель-потомок не работает - PullRequest
2 голосов
/ 08 июля 2011

Я пытаюсь запустить следующий код как подпроцесс

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

Этот скрипт отлично работает: запись в stdin, чтение из stdout и из 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()

Но этот сценарий не может прочитать любой вывод из stdout и блокируется там, даже несмотря на то, что программа C печатает на stdout перед запросом какого-либо ввода. Почему я ничего не могу прочитать с 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()

Ответы [ 2 ]

2 голосов
/ 08 июля 2011

Сначала необходимо очистить поток.Это обеспечит запись всех данных в поток.

#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;
}

По умолчанию stderr не буферизовано, поэтому вам не нужно его сбрасывать. stdout однако полностью буферизуется, если только он не указывает на терминал, тогда он буферизируется строкой (т. Е. \n автоматически вызовет сброс.

Посмотрите здесь , для setbuf () и setvbuf ().

0 голосов
/ 08 июля 2011

Я не вижу что-то вроде

stdout_data, stderr_data = p1.communicate()

в вашем коде

Popen.communicate (вход = нет)

Взаимодействие с процессом: отправка данных на стандартный ввод. Читайте данные из stdout и stderr, пока не будет достигнут конец файла. Подождите, пока процесс завершится. Необязательный входной аргумент должен быть строкой, которая должна быть отправлена ​​дочернему процессу, или None, если никакие данные не должны быть отправлены дочернему процессу.

connect () возвращает кортеж (stdoutdata, stderrdata).

Обратите внимание, что если вы хотите отправить данные в стандартный процесс, вам нужно создать объект Popen с stdin = PIPE. Точно так же, чтобы получить что-либо кроме None в кортеже результата, вам нужно также указать stdout = PIPE и / или stderr = PIPE.

Примечание. Считываемые данные буферизируются в памяти, поэтому не используйте этот метод, если размер данных большой или неограниченный.

См. docs.python.org

Функция, которую я держу в своем служебном поясе, чтобы обернуть вызов внешней программы с использованием подпроцесса, выглядит так (измените в соответствии с вашими потребностями):

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'))

Просто поместите вашу команду так, как вы написали бы ее в строке cmd в переменной, вызовите функцию, например ::1010 *

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