1

I am writing a Python program which runs a virtual terminal. Currently I am launching it like so:

import pexpect, thread

def create_input(child, scrollers, textlength=80, height=12):
    while 1:
        newtext = child.readline()
        print newtext

child = pexpect.spawn("bash", timeout=30000)

thread.start_new_thread(create_input,(child))

This works, and I can send commands to it via child.send(command). However, I only get entire lines as output. This means that if I launch something like Nano or Links, I don't receive any output until the process has completed. I also can't see what I'm typing until I press enter. Is there any way to read the individual characters as bash outputs them?

chown
  • 51,908
  • 16
  • 134
  • 170
Skyler
  • 909
  • 1
  • 10
  • 24
  • You would need to make the output "unbuffered", as it appears to be "line buffered" at the moment. – chown Nov 29 '11 at 18:35

2 Answers2

2

You would need to change the output of whatever program bash is running to be unbuffered instead of line buffering. A good amount of programs have a command line option for unbuffered output.

The expect project has a tool called unbuffer that looks like it can give you all bash output unbuffered. I have personally never used it, but there are other answers here on SO that also recommend it: bash: force exec'd process to have unbuffered stdout

Community
  • 1
  • 1
chown
  • 51,908
  • 16
  • 134
  • 170
  • This works except not for nano, links, vi etc. Vi tells me: `Vim: Warning: Output is not to a terminal.` – Skyler Nov 29 '11 at 19:31
  • @user677624 Hmm, I know there is a way to sort of "fake" being a terminal so that it works with vi/nano/etc... I'll try to find it again and include it. – chown Nov 29 '11 at 20:24
  • @user677624 I read something that said using `os.system` instead of `pexpect.spawn` would make this work for Vim, but I cannot confirm that. I'll try to find something more concrete. – chown Nov 29 '11 at 20:28
  • `os.system` doesn't seem to allow me to interact with it. – Skyler Nov 29 '11 at 21:17
  • Upon further research, it appears that programs such as Vi, Nano etc. write to a second buffer which is not (as far as I know) accessible from Python. Oh well. Unbuffer works great for bash though. – Skyler Dec 07 '11 at 17:45
1

The problem is lies in something else. If you open an interactive shell normally a terminal window is opened that runs bash, sh, csh or whatever. See the word terminal!

In the old days, we connected a terminal to a serial port (telnet does the same but over ip), again the word terminal.

Even a dumb terminal respond to ESC codes, to report its type and to set the cursor position, colors, clear screen etc.

So you are starting a subprocess with interactive output, but there is no way in telling that shell and subprocesses are to a terminal in this setup other than with bash startup parameters if there are any.

I suggest you enable telnetd but only on localhost (127.0.0.1) Within your program, make a socket and connect to localhost:telnet and look up how to emulate a proper terminal. If a program is in line mode you are fine but if you go to full screen editing, somewhere you will need an array of 80x24 or 132x24 or whatever size you want to store its characters, color. You also need to be able to shift lines up in that array.

I have not looked but I cannot imagine there is no telnet client example in python, and a terminal emu must be there too!

Another great thing is that telnet sessions clean up if the the ip connection is lost, eliminating ghost processes.

Martijn

Martijn
  • 26
  • 1
  • This might be an inspiration suitable for your needs: http://antony.lesuisse.org/software/ajaxterm/ Martijn – Martijn Mar 23 '12 at 18:40