Take the 2-minute tour ×
Server Fault is a question and answer site for professional system and network administrators. It's 100% free, no registration required.

I have got this little python3 script test.py:

import sys

print('test1')
test1 = sys.stdin.read()
print('test2')
test2 = sys.stdin.read()

print(test1)
print(test2)

And I would like to run this script remotely via ssh like this:

ssh srvid 'cd; python3 test.py'

I would expect that program prints test1, then will wait for input, and then prints test2 and again wait for input.

But the behaviour is slightly different:

ssh srvid 'cd; python3 test.py'
hell
test1
test2
hell

The program first waited for input. I have entered hell and pressed enter and then ctr+d for eof. Script did not wait for second input, and printed out test1 and test2.

It seems, that stdin / stdout are somehow blocked.

I tried same example in bash:

#!/bin/bash

echo "Hello world";
read test;
echo "helloworld 2";
read test2;
echo $test;
echo $test2;

When I invoked this script via ssh, everything worked as I am expecting.

Can somebody help me?

share|improve this question
2  
Do you do the same thing with ssh -t host 'command'? –  Zoredache Sep 30 '11 at 21:34
    
Wow, no... when I use -t switch everything works. Thank you very much!! You can add the answer for acception :-) –  JoshuaBoshi Sep 30 '11 at 21:42
    
When you specify a command for ssh to execute it assumes the command is noninteractive and doesn't allocate a pseudoterminal. The -t forces pty allocation. –  MikeyB Oct 1 '11 at 0:18
add comment

1 Answer

up vote 1 down vote accepted

This is due to a libc convention for stdio buffering. If stdout is a tty, it is typically line-buffered; fully buffered otherwise.

As others have suggested, passing the -t flag to ssh forces psuedo-tty allocation, and you get line-buffering as a result.

However, you could also explicitly flush stdout to get a similar result, as in:

import sys

print('test1')
sys.stdout.flush()
test1 = sys.stdin.readline() # ctrl+d and .read() effectively closes 
print('test2')               # stdin for the duration
sys.stdout.flush()
test2 = sys.stdin.readline()

print(test1)
print(test2)
# flushing happens implicitly when the stream is closed

Another option, would be to run python in totally unbuffered mode with the -u flag, as in

ssh srvid 'cd; python3 -u test.py'

Additional workarounds can be found in this stackoverflow question.


The program first waited for input. I have entered hell and pressed enter and then ctr+d for eof. Script did not wait for second input, and printed out test1 and test2.

I'm pretty sure the script didn't stop at the second input because you sent it an EOF during the first.


FWIW, I would probably write the python this way, unless you need multi-line input. It's a closer comparison to your bash example, IMO.

#!/usr/bin/env python3

print('test1')
test1 = input() # raw_input() in python 2.x
print('test2')         
test2 = input()

print(test1)
print(test2)
share|improve this answer
    
Thank you very much for explanation. I was thinking about flushing for a while, but I did not give it a try. Btw, I needed multi-line input :-) –  JoshuaBoshi Oct 4 '11 at 9:55
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.