2012-03-18 5 views
4

J'ai deux fichiers premier est fizztuyauterie immédiate avec python

#!/usr/bin/python               
import time 

print 'started' 
time.sleep(3) 
print 'ended' 

suivante qui est bar

#!/usr/bin/python               
import sys 

for line in sys.stdin: 
    print line 

Quand je lance la commande ./fizz | ./bar je pense à imprimer started puis attendre 3 secondes et imprimer ended, mais ce qui se passe vraiment, c'est qu'il imprime started et ended en même temps après 3 secondes. Y a-t-il un moyen d'obtenir mon comportement désiré? Merci

Répondre

5

Bonne question. C'est un peu plus difficile qu'il ne le devrait.

Le problème est en effet dans bar, spécifiquement sys.stdin étant tamponné. J'ai essayé d'ouvrir sys.stdin avec une taille de tampon plus petite et en utilisant python -u mais cela n'a pas fonctionné. La page de manuel a ceci à dire:

-u  Force stdin, stdout and stderr to be totally unbuffered. On 
      systems where it matters, also put stdin, stdout and stderr in 
      binary mode. Note that there is internal buffering in xread‐ 
      lines(), readlines() and file-object iterators ("for line in 
      sys.stdin") which is not influenced by this option. To work 
      around this, you will want to use "sys.stdin.readline()" inside 
      a "while 1:" loop. 

En fin de compte c'est ce qui a fonctionné pour moi:

#!/usr/bin/python             
import sys 
import os 

while True: 
    line = sys.stdin.readline() 
    if not line: 
     break 
    sys.stdout.write(line) # or print, doesn't matter. 
+0

+ 1 question si vous pensez que c'est une bonne question: D – Doboy

+1

@Doboy: Je l'ai fait, c'est mon seul vote là :) –

5

Maintenant qu'il est clair que le problème est du côté de la réception, je présenter une alternative que je préfère utiliser:

#!/usr/bin/python             
import sys 
import os 

for line in iter(sys.stdin.readline, ''): 
    sys.stdout.write(line) # \n included in line 

iter(func, sentinel) appels func() pour chaque itération et se termine si le résultat de la fonction == sentinel.

1

Il y a deux problèmes:

  1. print "something" dans ./foo ne pas vider son tampon de sortie standard si elle est redirigé (à la conduite dans ce cas), à savoir, lorsque stdout is not connected a tty-like device par exemple, à une console interactive
  2. for line in sys.stdin: peut essayer de lire plusieurs lignes à la fois

Vous pouvez le fixer comme suit:

$ PYTHONUNBUFFERED=1 ./foo | ./bar 
./bar

Où:

#!/usr/bin/python 
import sys 

for line in iter(sys.stdin.readline, ''): 
    print line, 

à-dire faire sans tampon stdout de ./foo (-u option) et lire l'entrée en ./bar ligne par ligne comme suggéré dans @Eduardo Ivanec's answer. Comme alternative, vous pouvez appeler sys.stdout.flush() dans ./foo au lieu de faire son stdout unbuffered comme suggéré dans @kev's answer.