Subject: Re: Interacting with external program -pty? - DN [1]


"Michael P. Reilly" <arcege@shore.net> - 19 Jan 2000 - comp.lang.python

 Niklas.Blomberg@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

Last modified
2000-02-10

(195.108.246.50)

Note: you are looking at
the snapshot of an old wiki
- much of this information
is likely to be very outdated