tags:

views:

123

answers:

4

Hi, I'm running a script to manage processes on a remote (SSH) machine. Let's call it five.py

#!/usr/bin/python
import time, subprocess

subprocess.call('echo 0',shell=True)
for i in range(1,5):
   time.sleep(1)
   print(i)

If i now run

ssh user@host five.py

I would like to see the output

0
1
2
3
4

appear on my standard out second by second (as it does if execute locally).. What happens is: I get the 0 from "echo" right away and the rest only appears at once after the entire program finishes. (Doesn't help to nest 'five.py' into a bash script; to call it by 'python five.py'; or to use 'print >> sys.stdout, i').

This must be related to the way python writes to stdout, since other programs behave quite normal.. A functional workaround is

import time, subprocess
import sys

subprocess.call('echo 0',shell=True)
for i in range(1,5):
  time.sleep(1)
  sys.stdout.write(str(i)+'\n')
  sys.stdout.flush()

But there must be a better solution than changing all my print statements!

A: 

A possible solution found in another topic, suggests I use

ssh -t user@host ./five.py

which fakes a terminal. Only drawback, ssh prints

Connection to host closed.

in addition.

cycyc
A: 

You can replace the sys.stdout object so that it automatically flushes after each write. This will also affect the print statement. An example, taken from this answer:

class flushfile(object):
    def __init__(self, f):
        self.f = f
    def write(self, x):
        self.f.write(x)
        self.f.flush()

import sys
sys.stdout = flushfile(sys.stdout)

Edit: Another option is to start Python with the -u option, which will force input and output to be unbuffered.

interjay
+2  A: 

You can add the -u on the shebang line as interjay hinted

#!/usr/bin/python -u

You could also reopen stdout with buffering turned off or set to line buffering

import os,sys
sys.stdout = os.fdopen(sys.stdout.fileno(), 'w', 0) # no buffering
sys.stdout = os.fdopen(sys.stdout.fileno(), 'w', 1) # line buffering

Usually line buffering is a good choice

gnibbler
Thanks a lot: 'sys.stdout = os.fdopen(sys.stdout.fileno(), 'w', 1)' works very well and should be more secure than 'python -u'
cycyc
A: 

One thing you might look at using since you are already using Python is Paramiko, much nicer way to do remote SSH work. Here is an article about how I am using it in its most basic form.

fuzzy lollipop