The following procedures are similar to the popen
and
pclose
system routines. The code is in a separate “popen”
module24:
(use-modules (ice-9 popen))
Execute a command in a subprocess, with a pipe to it or from it, or with pipes in both directions.
open-pipe
runs the shell command using ‘/bin/sh -c’.
open-pipe*
executes prog directly, with the optional
args arguments (all strings).
mode should be one of the following values. OPEN_READ
is
an input pipe, ie. to read from the subprocess. OPEN_WRITE
is an output pipe, ie. to write to it.
For an input pipe, the child’s standard output is the pipe and
standard input is inherited from current-input-port
. For an
output pipe, the child’s standard input is the pipe and standard
output is inherited from current-output-port
. In all cases
the child’s standard error is inherited from
current-error-port
(see Default Ports for Input, Output and Errors).
If those current-X-ports
are not files of some kind, and hence
don’t have file descriptors for the child, then /dev/null is
used instead.
Care should be taken with OPEN_BOTH
, a deadlock will occur if
both parent and child are writing, and waiting until the write completes
before doing any reading. Each direction has PIPE_BUF
bytes of
buffering (see Buffering), which will be enough for small writes,
but not for say putting a big file through a filter.
Equivalent to open-pipe
with mode OPEN_READ
.
(let* ((port (open-input-pipe "date --utc")) (str (read-line port))) ; from (ice-9 rdelim) (close-pipe port) str) ⇒ "Mon Mar 11 20:10:44 UTC 2002"
Equivalent to open-pipe
with mode OPEN_WRITE
.
(let ((port (open-output-pipe "lpr"))) (display "Something for the line printer.\n" port) (if (not (eqv? 0 (status:exit-val (close-pipe port)))) (error "Cannot print")))
Equivalent to open-pipe
with mode OPEN_BOTH
.
Close a pipe created by open-pipe
, wait for the process to
terminate, and return the wait status code. The status is as per
waitpid
and can be decoded with status:exit-val
etc
(see Processes)
waitpid WAIT_ANY
should not be used when pipes are open, since
it can reap a pipe’s child process, causing an error from a subsequent
close-pipe
.
close-port
(see Ports) can close a pipe, but it doesn’t reap
the child process.
The garbage collector will close a pipe no longer in use, and reap the
child process with waitpid
. If the child hasn’t yet terminated
the garbage collector doesn’t block, but instead checks again in the
next GC.
Many systems have per-user and system-wide limits on the number of processes, and a system-wide limit on the number of pipes, so pipes should be closed explicitly when no longer needed, rather than letting the garbage collector pick them up at some later time.
Execute a pipeline of commands, where each command is a list of a program and its arguments as strings, returning an input port to the end of the pipeline, an output port to the beginning of the pipeline and a list of PIDs of the processes executing the commands.
(let ((commands '(("git" "ls-files") ("tar" "-cf-" "-T-") ("sha1sum" "-"))) (success? (lambda (pid) (zero? (status:exit-val (cdr (waitpid pid))))))) (receive (from to pids) (pipeline commands) (let* ((sha1 (read-delimited " " from)) (index (list-index (negate success?) (reverse pids)))) (close to) (close from) (if (not index) sha1 (string-append "pipeline failed in command: " (string-join (list-ref commands index))))))) ⇒ "52f99d234503fca8c84ef94b1005a3a28d8b3bc1"
This module is only available on systems where the
popen
feature is provided (see Common Feature Symbols).