
andrea ambú
Tengo dos programas que estoy usando de esta manera:
$ c_program | python_program.py
c_program imprime algo usando printf()
y python_program.py lee usando sys.stdin.readline()
Me gustaría hacer que python_program.py procese la salida de c_program a medida que se imprime, inmediatamente, para que pueda imprimir su propia salida actual. Desafortunadamente, python_program.py obtiene su entrada solo después de que finaliza c_program.
¿Como puedo resolver esto?

marca4o
Simplemente configure stdout para que tenga un búfer de línea al comienzo de su programa C (antes de realizar cualquier salida), así:
#include <stdio.h>
setvbuf(stdout, NULL, _IOLBF, 0);
o
#include <stdio.h>
setlinebuf(stdout);
Cualquiera de los dos funcionará en Linux, pero setvbuf
es parte del estándar C, por lo que funcionará en más sistemas.
De forma predeterminada, la salida estándar se almacenará en bloque para una tubería o un archivo, o se almacenará en línea para una terminal. Dado que stdout es una canalización en este caso, el valor predeterminado será el bloque almacenado en búfer. Si tiene un búfer de bloque, el búfer se vaciará cuando esté lleno o cuando llame fflush(stdout)
. Si tiene un búfer de línea, se vaciará automáticamente después de cada línea.
Lo que necesita es que su programa C llame a fflush(stdout) después de cada línea. Por ejemplo, con la herramienta grep de GNU, puede invocar la opción ‘–line-buffered’, que provoca este comportamiento. Ver descarga.

bonitorobot
Si puede modificar su programa C, ya recibió su respuesta, pero pensé en incluir una solución para aquellos que no pueden/no quieren modificar el código.
esperar tiene un script de ejemplo llamado unbuffer eso hará el truco.
Es posible que desee probar flush
ing el flujo de salida estándar en el programa cpp.
Todos los shells de Unix (que yo sepa) implementan tuberías de shell a través de algo más que un pty (¡normalmente, usan tuberías de Unix!-); por lo tanto, la biblioteca de tiempo de ejecución de C/C++ en cpp_program
SABRÁ que su salida NO es una terminal y, por lo tanto, SABRÁ la salida (en fragmentos de unos pocos KB a la vez). A menos que escriba su propio shell (o semiquasimaybeshelloid) que implemente canalizaciones a través de pyt, creo que no hay forma de hacer lo que necesita utilizando la notación de canalización.
La cosa “shelloide” en cuestión podría estar escrita en Python (o en C, o Tcl, o…), usando el pty
módulo de la biblioteca estándar o abstracción de nivel superior basada en él, como espero, y el hecho de que los dos programas que se conectarán a través de una “tubería basada en pty” estén escritos en C++ y Python es bastante irrelevante. La idea clave es engañar al programa a la izquierda de la tubería para que crea que su salida estándar es una terminal (es por eso que un pty debe estar en la raíz del truco) para engañar a su biblioteca de tiempo de ejecución para que NO almacene la salida en búfer. Una vez que haya escrito tal shelloide, lo llamará con alguna sintaxis como:
$ shelloid ‘cpp_programa | programa_python.py’
Por supuesto, sería más fácil proporcionar una “solución puntual” escribiendo python_program
a sabiendas de que debe engendrar cpp_program
como un subproceso Y engañarlo para que crea que su salida estándar es una terminal (es decir, python_program
entonces usaría directamente pexpect
, por ejemplo). Pero si tiene un millón de situaciones en las que desea anular el almacenamiento en búfer normal realizado por la biblioteca de tiempo de ejecución C proporcionada por el sistema, o muchos casos en los que desea reutilizar los filtros existentes, etc., escribiendo shelloid
en realidad podría ser preferible.

Abu Aqil
ok, esto tal vez suene estúpido, pero podría funcionar:
salida de su pgm a un archivo
$ c_program >> ./out.log
desarrollar un programa de python que lea desde el comando 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"
¿De cuánta producción estás hablando? Hay búferes involucrados, por lo que cualquier cosa por debajo de 4K siempre será una sola cosa.
– S. Lott
11 de septiembre de 2009 a las 2:14
no hay manera de decidir cuando el búfer debe ser vaciado?
– Andrea Ambú
11 de septiembre de 2009 a las 2:23