1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374 |
- ;; The following code is from
- ;; [[https://www.draketo.de/software/guile-capture-stdout-stderr.html]].
- ;; Comments and some formatting by me.
- ;; Related links:
- ;; https://www.gnu.org/software/guile/manual/html_node/Pipes.html
- ;; https://www.gnu.org/software/guile/manual/guile.html#Ports-and-File-Descriptors
- ;; This is an example of how you can write a procedure, which allows you to run
- ;; a shell command from GNU Guile and capture not only its stdout output in a
- ;; string, but also its stderr output in a string. This can be useful, if you
- ;; need to parse the output of both stdout and stderr.
- (import
- (ice-9 rdelim)
- (ice-9 popen)
- (rnrs io ports))
- ;; The procedure is named in the same manner as call-with-output-string or
- ;; call-with-output-file for example.
- (define (call-command-with-output-error-to-string cmd)
- ;; (pipe) creates 2 linked ports as a pair. The car is an input port and cdr
- ;; is an output port. What goes in to the input port comes out at the output
- ;; port.
- (let* ([err-cons (pipe)]
- [port
- ;; Set up a scope in which the stderr will be written to a given port.
- (with-error-to-port (cdr err-cons)
- (λ ()
- ;; Run a command in a subprocess, with mode OPEN_READ, using the
- ;; open-pipe procedure. The open-pipe procedure runs the shell
- ;; command using "/bin/sh -c".
- ;; Return an input pipe, because it is open-pipe with OPEN_READ.
- ;; The command is already run here. The output of the command will
- ;; be available from the input pipe.
- ;; See:
- ;; [[https://www.gnu.org/software/guile/manual/html_node/Pipes.html]]
- (open-input-pipe cmd)))]
- ;; Set the input port to blocking, if there is more than (* 1024 1024
- ;; 16) bytes.
- [_ (setvbuf (car err-cons)
- 'block
- ;; 16 megabytes (byte * 1024 -> kilobyte, kilobyte * 1024
- ;; -> megabyte, megabyte * 16 -> 16 megabytes)
- (* 1024 1024 16))]
- ;; Read everything from port until a character of the given string is
- ;; encountered. No character is in the string, so everything is read
- ;; from the port, until EOF is encountered.
- [result (read-delimited "" port)])
- ;; We already have the result from the command at this point. All that is
- ;; left to do is to output the result appropriately.
- ;; Make sure the port is properly closed. Nothing more shall be written to
- ;; the port, as the command has already been sent and run.
- (close-port (cdr err-cons))
- ;; Return 2 values, one is the stdout output of the command and one is the
- ;; strerr output of the command.
- (values result
- ;; read-delimited from (ice-9 rdelim) reads from the port until a
- ;; character from the string "" is encountered or stops at
- ;; EOF. Since "" is empty, it means, that all will be read until EOF
- ;; is encountered.
- (read-delimited "" (car err-cons)))))
- (call-command-with-output-error-to-string "echo 1; echo 2 >&2")
|