[GRASS-dev] python scripts and standard input

Glynn Clements glynn at gclements.plus.com
Wed Apr 28 17:16:45 EDT 2010

Massimo Di Stefano wrote:

> i'm tring to use grass modules that needs a "standard input" method,
> like "m.proj"
> here an example where i'musing a "file" as input :
> coords = read_command('m.proj', input=coordsfile, flags='i') 
> how to use standard input, like in bash :
> echo '599537.80 4920995.38' | m.proj -o
> there is a python way to do it, or i need to use "system call" like
> os.system or subprocess ?

If you want to read from the child's stdout, there's pipe_command()
and read_command(). If you want to write to the child's stdin, there's
feed_command() and write_command().

If you want to do both, you need to do it yourself using
start_command() (on which the other functions are based), e.g.:

import grass.script as grass

def read_write_command(*args, **kwargs):
    input = kwargs['stdin']
    kwargs['stdout'] = grass.PIPE
    kwargs['stdin'] = grass.PIPE
    ps = grass.start_command(*args, **kwargs)
    return ps.communicate(input)[0]

This behaves like a combination of read_command() and write_command(). 
The input string is passed via the "stdin" parameter as for
write_command(), while the data from the child's stdout is returned as
for read_command().

If you want a pipe_command/feed_command interface with file handles,
it gets problematic. You need to use non-blocking I/O or multiple
threads; otherwise, you can get deadlock, with the child blocked
waiting for the parent to read the child's stdout while the parent is
blocked writing to the child's stdin.

If you really need this, look at the implementation of
subprocess.communicate(); the Unix version uses select() while Windows
uses threads.

Alternatively, redirect the child's stdout to a file and have the
parent read the file; writing to a file never blocks.

BTW, if you need even lower-level access, use grass.Popen() or
grass.call(). These are almost identical to subprocess.Popen() and
subprocess.call() except that, on Windows, they set shell=True by
default. This allows commands to be either scripts or binary
executables, and doesn't require the extension; with shell=False, the
command must be a binary executable and must include the ".exe"

Glynn Clements <glynn at gclements.plus.com>

More information about the grass-dev mailing list