2009-09-11 7 views
10

la sortie en entrée d'un autre programme que j'ai deux programmes que je utilise de cette façon:Obtenir à la volée

$ c_program | python_program.py 

imprime c_program quelque chose en utilisant printf() et python_program.py lectures en utilisant sys.stdin.readline()

Je d aimer que python_program.py traite la sortie de c_program au fur et à mesure de l'impression, afin qu'elle puisse imprimer sa propre sortie courante. Malheureusement, python_program.py reçoit son entrée uniquement après la fin du programme c_program.

Comment puis-je résoudre ce problème?

+0

De quelle sortie parlez-vous? Il y a des tampons impliqués, donc tout ce qui est sous 4K sera toujours une seule chose. –

+0

est-il impossible de décider * quand * le tampon doit être rincé? –

Répondre

17

stdout Il suffit de définir pour être mis en mémoire tampon au début de votre programme C (avant d'effectuer toute sortie), comme ceci:

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

ou

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

Soit on va travailler sur Linux, mais setvbuf fait partie de la norme C pour qu'il fonctionne sur plusieurs systèmes. Par défaut, stdout sera mis en mémoire tampon pour un canal ou un fichier, ou une ligne mise en mémoire tampon pour un terminal. Puisque stdout est un pipe dans ce cas, la valeur par défaut sera block buffer. S'il est tamponné par un bloc, le tampon sera vidé lorsqu'il est plein ou lorsque vous appelez fflush(stdout). S'il est tamponné, il sera automatiquement vidé après chaque ligne.

+0

setvbuf fonctionne comme un charme. Merci! –

+0

merci beaucoup. cela m'a aidé dans srcds_linux pour écrire un restarter. Je l'ai simplement mis en plugin dans ce serveur de jeu et voila .. stdout arrive en ligne et pas en morceaux de 4k. – GottZ

1

Tous les shells Unix (que je connais) mettent en œuvre des pipelines shell via autre chose qu'un pty (typiquement, ils utilisent des tuyaux Unix!); par conséquent, la bibliothèque d'exécution C/C++ dans cpp_program SAVIT que sa sortie n'est PAS un terminal, et par conséquent, il va buffer la sortie (dans les morceaux de quelques Ko à la fois). Sauf si vous écrivez votre propre shell (ou semiquasimaybeshelloid) qui implémente des pipelines via pyt, je crois qu'il n'y a aucun moyen de faire ce que vous avez besoin en utilisant la notation pipeline. La chose "shelloid" en question pourrait être écrite en Python (ou en C, ou Tcl, ou ...), en utilisant le module pty de la bibliothèque standard ou de l'abstraction de plus haut niveau basée dessus comme pexpect, et le fait que les deux programmes à être connectés via un "pipeline basé sur pty" sont écrits en C++ et Python est assez hors de propos. L'idée clé est de tromper le programme à la gauche de la pipe en lui faisant croire que stdout est un terminal (c'est pourquoi un pty doit être à la racine de l'astuce) pour tromper sa bibliothèque d'exécution en sortie NOT buffering. Une fois que vous avez écrit un tel shelloid, vous l'appelez avec une syntaxe telle que:

$ shelloid 'cpp_program | python_program.py »

Bien sûr, il serait plus facile de fournir une « solution ponctuelle » en écrivant python_program en sachant qu'il doit engendrer cpp_program comme un sous-processus et bidouiller en croyant que son stdout est un terminal (c.-à- python_program utiliserait alors directement pexpect, par exemple). Mais si vous avez un million de ces situations où vous voulez vaincre la mise en mémoire tampon normale effectuée par la bibliothèque d'exécution C fournie par le système ou plusieurs cas dans lesquels vous souhaitez réutiliser des filtres existants, écrire shelloid peut être préférable.

1

Vous pouvez essayer flush en utilisant le flux stdout dans le programme cpp.

8

Ce dont vous avez besoin, c'est que votre programme C appelle fflush (stdout) après chaque ligne. Par exemple, avec l'outil GNU grep, vous pouvez appeler l'option '--line-buffered', ce qui provoque ce comportement. Voir fflush.

-1

ok ce son peut-être stupide, mais il pourrait fonctionner:

la sortie de votre pgm dans un fichier

$ c_program >> ./out.log 

développer un programme python qui a lu de la commande de queue

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

Malheureusement pour vous, cela ne fonctionnera pas. Le problème est principalement que la sortie du programme C est tamponnée, et il n'y a rien que vous pouvez faire dans le programme Python pour affecter cela. Vous devez corriger le programme C afin que sa sortie ne soit pas tamponnée même si la sortie est envoyée à un tube. –

6

Si vous pouvez modifier votre programme C, vous avez déjà reçu votre answer mais j'ai pensé que j'inclurais une solution pour ceux qui ne peuvent/ne veulent pas modifier le code.

expect a un exemple de script appelé unbuffer qui fera l'affaire.