views:

413

answers:

4

I want to write a program that reads stdin (unbuffered) and writes stdout (unbuffered) doing some trivial char-by-char transformation. For the sake of the example let's say I want to remove all chars x from stdin.

+6  A: 

Read from sys.stdin and write to sys.stdout (or use print). Your example program:

import sys

for line in sys.stdin:
    print line.replace("x", ""),

There isn't a standard way to make stdin unbuffered, and you don't want that. Let the OS buffer it.

Jed Smith
He did say "unbuffered" but I'm not sure it really matters.
Chris Lutz
I edited my answer as you commented.
Jed Smith
+5  A: 

I don't know exactly what you mean by buffered in this context, but it is pretty simple to do what you are asking...

so_gen.py (generating a constant stream that we can watch):

import time
import sys
while True:
    for char in 'abcdefx':
        sys.stdout.write(char)
        sys.stdout.flush()
        time.sleep(0.1)

so_filter.py (doing what you ask):

import sys
while True:
    char = sys.stdin.read(1)
    if not char:
        break
    if char != 'x':
        sys.stdout.write(char)
        sys.stdout.flush()

Try running python so_gen.py | python so_filter.py to see what it does.

Mike Boers
winner for writing `if not char: break`
flybywire
@flybywire: His answer needed it, no other answer did...
Jed Smith
+2  A: 

You can use the fileinput class, which lets you process inputs like the Perl diamond operator would. From the docs:

import fileinput
for line in fileinput.input():
    process(line)

where process does something like print line.replace('x','').

You can follow this StackOverflow question for how to unbuffer stdout. Or you can just call sys.stdout.flush() after each print.

Emil
Ah! This makes all the extra work I was doing because I missed Perl for naught! I need to go through the Python standard library very closely.
Chris Lutz
+1  A: 

Use the -u switch for the python interpreter to make all reads and writes unbuffered. Similar to setting $| = true; in Perl. Then proceed as you would, reading a line modifying it and then printing it. sys.stdout.flush() not required.

#!/path/to/python -u

import sys

for line in sys.stdin:
    process_line(line)
EmFi