Получение другой программы в качестве входного сигнала на лету

У меня есть две программы, которые я использую таким образом:

$ c_program | python_program.py

c_program печатает что-то с помощью printf() и python_program.py читает с помощью sys.stdin.readline()

Я хотел бы сделать вывод c_program процесса python_program.py, когда он печатает, немедленно, чтобы он мог распечатать свой собственный текущий вывод. К сожалению, python_program.py получает свой вход только после завершения c_program.

Как я могу это решить?

Ответ 1

Просто установите stdout для буферизации строк в начале вашей C-программы (перед выполнением любого вывода), например:

#include <stdio.h>
setvbuf(stdout, NULL, _IOLBF, 0);

или

#include <stdio.h>
setlinebuf(stdout);

Либо один будет работать в Linux, но setvbuf является частью стандарта C, поэтому он будет работать на других системах.

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

Ответ 2

Что вам нужно, так это то, что ваша программа C вызывается fflush (stdout) после каждой строки. Например, с помощью инструмента GNU grep вы можете вызвать параметр "-line-buffered", который вызывает это поведение. См. fflush.

Ответ 3

Если вы можете изменить свою программу на C, вы уже получили ответ , но я подумал, что я бы включил решение для тех, кто не может /t изменить код.

expect имеет пример script, называемый unbuffer, который сделает трюк.

Ответ 4

Все оболочки Unix (которые я знаю) реализуют конвейеры оболочки через что-то еще, чем pty (обычно они используют Unix-каналы!); поэтому библиотека времени выполнения C/С++ в cpp_program будет значить, что ее вывод НЕ является терминалом, и поэтому он будет буферизовать вывод (в кусках по несколько килобайт за раз). Если вы не пишете свою собственную оболочку (или semiquasimaybeshelloid), которая реализует конвейеры через pyt's, я считаю, что нет способа сделать то, что вам нужно, используя нотацию конвейера.

"Оклелоидная" вещь может быть написана на Python (или в C, или Tcl или...), используя модуль pty стандартной библиотеки или абстракцию более высокого уровня на основе этого, например pexpect, и тот факт, что две программы, которые будут подключены через "конвейер, основанный на pty", записываются на С++, а Python довольно неуместен, Основная идея состоит в том, чтобы обмануть программу слева от трубы, полагая, что ее stdout является терминалом (то, почему pty должен быть в корне трюка), чтобы обмануть его библиотеку времени выполнения в НЕ буферизующий вывод. После того, как вы написали такой оклелоид, вы бы назвали его с некоторым синтаксисом, например:

$shelloid 'cpp_program | python_program.py

Конечно, было бы проще предоставить "точечное решение", написав python_program в знании, что он должен порождать cpp_program как подпроцесс И обмануть его, полагая, что его stdout является терминалом (т.е. python_program тогда будет непосредственно использовать pexpect, например). Но если у вас есть миллион таких ситуаций, когда вы хотите победить нормальную буферизацию, выполняемую системной библиотекой времени C, или во многих случаях, когда вы хотите повторно использовать существующие фильтры и т.д., Писать shelloid может быть предпочтительнее.

Ответ 5

Возможно, вы захотите попробовать flush в потоке stdout в программе cpp.

Ответ 6

ОК, возможно, это звучит глупо, но это может сработать:

выводит ваш pgm в файл

$ c_program >> ./out.log

разработать программу python, которая считывает из команды tail

import os

tailoutput = os.popen("tail -n 0 -f ./out.log")

try:
    while 1:
        line = tailoutput.readline()
        if len(line) == 0:
            break

        #do the rest of your things here
        print line

except KeyboardInterrupt:
        print "Quitting \n"