Получение другой программы в качестве входного сигнала на лету
У меня есть две программы, которые я использую таким образом:
$ 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"