Interacting with external program -pty?

Michael P. Reilly arcege at shore.net
Wed Jan 19 12:51:27 EST 2000


Niklas.Blomberg at hassle.se.astra.com wrote:
: Dear all,

: I would appreciate some advice on how to script an external interactive
: process(program) using python. In addition to sending commands (which is
: straightforward) I need to be able to capture the output (which can be
: extensive) for further downstream processing. Since the program expects a
: terminal pipes don't work - the output is buffered - I have started to look
: at the pty module. This is uncharted territory for me and any advice both on
: possible solutions and perhaps availiable example code would be most
: appreciated.

: I'll be happy to post a summary.

There are a number of techniques you can use:

  1)  standard library module "pty"
      >>> import os, pty
      >>> master_fd, master_pty = pty.master_open()
      >>> slave_fd = pty.slave_open(master_pty)
      >>> os.write(master_fd, "hello\n")
      6
      >>> os.read(slave_fd, 6)
      'hello\012'
      >>> os.close(master_fd)
      >>> os.close(slave_fd)
    This needs to be wrapped with other code; there is a specialized
    "fork" function in the method.

  2)  the ExpectPy module (<URL: http://starship.python.net/~arcege/>)
      >>> import ExpectPy
      >>> spawn_id = Expectpy.spawn('/bin/cat', 'cat')
      >>> spawn_id.send('hello\r\n')
      >>> spawn_id.expect((ExpectPy.GLOB, "*\n", None))
      >>> spawn_id.match
      'hello\015\012hello\015\012'
      >>> spawn_id.close()
    The message prints twice because it would in /bin/cat at the
    terminal (cf. half versus full duplex).

  3)  depending on what you want: the standard library module "telnetlib"
    This module is to be used to interact with a telnet session (not
    with the telnet program).

  4)  fork, create pipes and exec
    This is the low-level stuff.
      >>> import os
      >>> def myspawn(*args):
      ...   (cld_reader, par_writer) = os.pipe()
      ...   (par_reader, cld_writer) = os.pipe()
      ...   pid = os.fork()
      ...   if pid:  # parent
      ...     os.close(cld_reader)
      ...     os.close(cld_writer)
      ...   else:    # child
      ...     os.close(0); os.dup(cld_reader)  # stdin
      ...     os.close(1); os.dup(cld_writer)  # stdout
      ...     os.close(2); os.dup(cld_writer)  # stderr
      ...     os.close(cld_reader); os.close(par_writer)
      ...     os.close(par_reader); os.close(cld_writer)
      ...     os.execvp(args[0], args)
      ...     os.exit(2)  # if we canot exec()
      ...   return (pid, (par_reader, par_writer))
      ...
      >>> (pid, pipe) = myspawn('cat')
      >>> os.write(pipe[1], 'hello\n')
      >>> os.read(pipe[0], 6)
      'hello\012'
      >>> os.close(pipe[3])
      >>> os.waitpid(pid, 0)
      (82572, 2)
      >>
    Notice that the stderr goes the to same location as stdout, just
    like pty's and terminals.  This can be changed tho. ;)

I hope this helps.
  -Arcege




More information about the Python-list mailing list