stdout-stderr.scm 3.1 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374
  1. ;; The following code is from
  2. ;; [[https://www.draketo.de/software/guile-capture-stdout-stderr.html]].
  3. ;; Comments and some formatting by me.
  4. ;; Related links:
  5. ;; https://www.gnu.org/software/guile/manual/html_node/Pipes.html
  6. ;; https://www.gnu.org/software/guile/manual/guile.html#Ports-and-File-Descriptors
  7. ;; This is an example of how you can write a procedure, which allows you to run
  8. ;; a shell command from GNU Guile and capture not only its stdout output in a
  9. ;; string, but also its stderr output in a string. This can be useful, if you
  10. ;; need to parse the output of both stdout and stderr.
  11. (import
  12. (ice-9 rdelim)
  13. (ice-9 popen)
  14. (rnrs io ports))
  15. ;; The procedure is named in the same manner as call-with-output-string or
  16. ;; call-with-output-file for example.
  17. (define (call-command-with-output-error-to-string cmd)
  18. ;; (pipe) creates 2 linked ports as a pair. The car is an input port and cdr
  19. ;; is an output port. What goes in to the input port comes out at the output
  20. ;; port.
  21. (let* ([err-cons (pipe)]
  22. [port
  23. ;; Set up a scope in which the stderr will be written to a given port.
  24. (with-error-to-port (cdr err-cons)
  25. (λ ()
  26. ;; Run a command in a subprocess, with mode OPEN_READ, using the
  27. ;; open-pipe procedure. The open-pipe procedure runs the shell
  28. ;; command using "/bin/sh -c".
  29. ;; Return an input pipe, because it is open-pipe with OPEN_READ.
  30. ;; The command is already run here. The output of the command will
  31. ;; be available from the input pipe.
  32. ;; See:
  33. ;; [[https://www.gnu.org/software/guile/manual/html_node/Pipes.html]]
  34. (open-input-pipe cmd)))]
  35. ;; Set the input port to blocking, if there is more than (* 1024 1024
  36. ;; 16) bytes.
  37. [_ (setvbuf (car err-cons)
  38. 'block
  39. ;; 16 megabytes (byte * 1024 -> kilobyte, kilobyte * 1024
  40. ;; -> megabyte, megabyte * 16 -> 16 megabytes)
  41. (* 1024 1024 16))]
  42. ;; Read everything from port until a character of the given string is
  43. ;; encountered. No character is in the string, so everything is read
  44. ;; from the port, until EOF is encountered.
  45. [result (read-delimited "" port)])
  46. ;; We already have the result from the command at this point. All that is
  47. ;; left to do is to output the result appropriately.
  48. ;; Make sure the port is properly closed. Nothing more shall be written to
  49. ;; the port, as the command has already been sent and run.
  50. (close-port (cdr err-cons))
  51. ;; Return 2 values, one is the stdout output of the command and one is the
  52. ;; strerr output of the command.
  53. (values result
  54. ;; read-delimited from (ice-9 rdelim) reads from the port until a
  55. ;; character from the string "" is encountered or stops at
  56. ;; EOF. Since "" is empty, it means, that all will be read until EOF
  57. ;; is encountered.
  58. (read-delimited "" (car err-cons)))))
  59. (call-command-with-output-error-to-string "echo 1; echo 2 >&2")