Name

ext:run-program — Start and communicate with a child process.

Function

(ext:run-program command argv &key input output error wait environ if-input-does-exist if-output-exists if-error-exists external-format)

input

One of :STREAM, T, NIL, string or pathname - defaults to :STREAM

output

One of :STREAM, T, NIL, string or pathname - defaults to :STREAM

error

One of :OUTPUT, :STREAM, T, NIL, string or pathname - defaults to :OUTPUT

wait

Boolean indicating if process should run synchronously, defaults to T

environ

List of strings containing environment bindings. Defaults to NIL (inheritance of lisp process environment).

if-input-does-not-exist

If :INPUT is pathname this symbol value is provided as :IF-DOES-NOT-EXIST for CL_OPEN. Defaults to NIL

if-output-exists

If :OUTPUT is pathname this symbol value is provided as :IF-EXISTS for CL_OPEN. Defaults to :ERROR

if-error-exists

If :ERROR is pathname this symbol value is provided as :IF-EXISTS for CL_OPEN. Defaults to :ERROR

external-format

External format used for both streams and pathnames. Defaults to :DEFAULT

returns

Two-way stream responsible for input/output with created process (created of :OUTPUT and :INPUT),

Return code of spawned process. If process still runs then NIL

ext:external-process structure holding process state.

Description

This function creates a external process by launching the program command with the arguments from the list argv.

The arguments input, output and error are used to intercept the standard input, output and error streams of the program. A value of :STREAM means a lisp stream will be created to communicate with the child process. A value of NIL means that the data from this pipe will be discarded. The value of T means that the child process will use the parent's standard input, output or error channels. If value is pathname, then corresponding file will be used (strings are coerced to pathnames).

For instance, if ECL writes to the console and you pass a value of output equal to T, the child process will also output to the console. Finally, the error messages of the child process are redirected to the same pipe as its standard output when error takes the value :OUTPUT.

If the child process was succesfully launched, this function outputs a lisp stream to which we one may write, read or do both things, depending on the arguments input and output. If an error happened during the preparation of the child process (for instance the program was not found), this function returns NIL.

Function returns three values - two-way stream for communication, return-code or nil depending if process is called asynchronously, and ext:external-process structure holding process state.

The design of this function is inspired by the function of same name in CMUCL and SBCL.

Example

List all users in a Unix system. We use the sed command to parse the file with the list of users, removing comments and information other than the user names:

(defun all-users (&optional (file "/etc/passwd"))
  (let ((s (ext:run-program "sed"
              (list "-e" "/^#.*$/d;/^[^:]*$/d;s,^\\([^:]*\\).*$,\\1,g"
                file)
              :input NIL :output :STREAM :error NIL)))
    (unless s
      (error "Unable to parse password file"))
    (loop for x = (read s NIL NIL)
          while x
          collect x)))
   

Make a directory. Redirect standard error output to the same as the output:

(ext:run-program "mkdir" '("./tmp") :output :STREAM :error :OUTPUT)
   

Same as before, but now both the output and the standard error are discarded

(ext:run-program "mkdir" '("./tmp") :output NIL :error :OUTPUT)
   

Limitations

All streams passed to ext:run-program has to have underlying file handler. That means, that if gray streams are passed to function - it might signal an error. Such situation occurs, when for instance :OUTPUT value is T and *standard-output* is bound to gray stream (default if using slime and emacs).