2009-09-11 2 views
10

Ich habe zwei Programme, die ich bin auf diese Weise mit:Erste anderen Programms Ausgabe als Eingabe on the fly

$ c_program | python_program.py 

c_program druckt etwas printf() und python_program.py mit liest mit sys.stdin.readline()

I‘ Ich möchte, dass python_program.py die Ausgabe von c_program so abarbeitet, wie sie sofort druckt, so dass sie ihre eigene aktuelle Ausgabe ausgeben kann. Unglücklicherweise erhält python_program.py erst nach dem Beenden von c_program seine Eingabe.

Wie kann ich das lösen?

+0

Wie viel Leistung sprechen Sie? Da sind Puffer beteiligt, also wird alles unter 4K immer eine einzige Sache sein. –

+0

gibt es keine Möglichkeit zu entscheiden * wann * der Puffer geleert werden soll? –

Antwort

17

Gerade gesetzt stdout zu Beginn des C - Programms (vor dem Ausführen einer Ausgabe) gepuffert werden:

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

oder

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

Entweder man wird unter Linux arbeiten, aber setvbuf ist Teil des C-Standard, so dass es mehr Systeme arbeiten wird.

Standardmäßig wird stdout blockweise für eine Pipe oder Datei gepuffert oder für ein Terminal gepuffert. Da stdout in diesem Fall eine Pipe ist, wird der Standardwert block gepuffert. Wenn der Block gepuffert ist, wird der Puffer gelöscht, wenn er voll ist oder wenn Sie fflush(stdout) aufrufen. Wenn es zwischengespeichert ist, wird es nach jeder Zeile automatisch geleert.

+0

setvbuf wirkt wie ein Zauber. Vielen Dank! –

+0

vielen Dank. Das hat mir in srcds_linux geholfen, einen Neustart zu schreiben. Ich stelle es einfach als Plugin in diesen Gameserver und voila .. stdout kommt in Zeilen und nicht in 4k Chunks. – GottZ

1

Alle Unix-Shells (die ich kenne) implementieren Shell-Pipelines über etwas anderes als eine Pty (normalerweise verwenden sie Unix-Pipes! -); Daher wird die C/C++ - Laufzeitbibliothek in cpp_program WISSEN, dass ihre Ausgabe kein Terminal ist, und daher Puffert sie die Ausgabe (in Blöcken von einigen KB zu einem Zeitpunkt). Es sei denn, Sie schreiben Ihre eigene Shell (oder semiquasimaybeshelloid), die Pipelines über pyt's implementiert, ich glaube, es gibt keine Möglichkeit, das zu tun, was Sie benötigen, indem Sie die Pipeline-Notation verwenden.

Die fragliche "Shelloid" -Ding könnte in Python (oder in C oder Tcl oder ...) geschrieben werden, mit dem pty Modul der Standardbibliothek oder höhere Abstraktion basierend darauf wie pexpect, und die Tatsache, dass die beiden Programme, die über eine "Pty-basierte Pipeline" verbunden werden sollen, in C++ und Python geschrieben sind, ist ziemlich irrelevant. Die Schlüsselidee ist, das Programm links von der Pipe zu glauben, dass es ein Terminal ist (deshalb muss ein pty an der Wurzel des Tricks sein), um seine Laufzeitbibliothek in die NICHT-Pufferausgabe zu täuschen. Sobald Sie solch ein Shelloid geschrieben haben, würden Sie es mit irgendeiner Syntax wie nennen:

$ shelloid 'cpp_program | python_program.py‘

Natürlich wäre es einfacher sein, eine‚Punkt-Lösung‘zu schaffen, durch python_program in dem Wissen, das Schreiben, dass es cpp_program als Unter Prozess erzeugen muß und Trick es in seine stdout zu glauben, einen Terminal (dh python_program würde dann direkt zB pexpect verwenden). Aber wenn Sie eine Million solcher Situationen haben, in denen Sie die normale Pufferung durch die vom System bereitgestellte C-Laufzeitbibliothek oder viele Fälle, in denen Sie vorhandene Filter usw. wiederverwenden möchten, vereiteln möchten, ist das Schreiben von shelloid möglicherweise tatsächlich vorzuziehen.

1

Sie können versuchen, flush den Stdout-Stream in der cpp-Programm.

8

Sie müssen Ihr C-Programm nach jeder Zeile fflush (stdout) aufrufen. Zum Beispiel können Sie mit dem GNU-Grep-Tool die Option '--line-buffered' aufrufen, die dieses Verhalten verursacht. Siehe fflush.

-1

ok dies vielleicht blöd klingen, aber es könnte funktionieren:

Ausgang Ihre pgm in eine Datei

$ c_program >> ./out.log 

ein Python-Programm entwickeln, das von Befehl tail lesen

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" 
+1

Leider funktioniert das nicht. Das Problem ist in erster Linie, dass die Ausgabe des C-Programms gepuffert ist, und es gibt nichts, was Sie im Python-Programm tun können, um dies zu beeinflussen. Sie müssen das C-Programm so anpassen, dass seine Ausgabe nicht gepuffert wird, selbst wenn die Ausgabe an eine Pipe geht. –

6

Wenn Sie Ihr C-Programm ändern können, haben Sie bereits Ihre answer erhalten, aber ich dachte, ich würde eine Lösung für diejenigen einschließen, die Code nicht ändern können/werden.

expect hat ein Beispielskript namens unbuffer, das den Trick tun wird.