Obtener la salida de otro programa como entrada sobre la marcha

4 minutos de lectura

avatar de usuario
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?

  • ¿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

avatar de usuario
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.

  • Muchísimas gracias. esto me ayudó en srcds_linux para escribir un reinicio. simplemente lo puse como complemento en ese servidor de juegos y listo… la salida estándar viene en líneas y no en fragmentos de 4k.

    – GottZ

    21/10/2012 a las 15:53

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.

avatar de usuario
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 flushing 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.

avatar de usuario
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"

¿Ha sido útil esta solución?

Esta web utiliza cookies propias y de terceros para su correcto funcionamiento y para fines analíticos y para mostrarte publicidad relacionada con sus preferencias en base a un perfil elaborado a partir de tus hábitos de navegación. Al hacer clic en el botón Aceptar, acepta el uso de estas tecnologías y el procesamiento de tus datos para estos propósitos. Configurar y más información
Privacidad