example-05-improved.scm 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102
  1. (import (ice-9 popen)
  2. (ice-9 textual-ports)
  3. (ice-9 binary-ports)
  4. (ice-9 exceptions)
  5. (ice-9 receive)
  6. (ice-9 match)
  7. (srfi srfi-11))
  8. (define read-from-write-to
  9. (lambda* (in-port out-port #:key (bytes-count 1024))
  10. "Read from an IN-PORT and write to OUT-PORT, BYTES-COUNT
  11. bytes at a time."
  12. (let loop ([bv (get-bytevector-n in-port bytes-count)])
  13. (unless (eof-object? bv)
  14. (put-bytevector out-port bv)
  15. (loop (get-bytevector-n in-port bytes-count))))))
  16. (define run-command
  17. (lambda* (cmd
  18. #:key
  19. (cmd-out-port (current-output-port))
  20. (err-out-port (current-error-port)))
  21. "Allow the user to give output port and error port to the
  22. function."
  23. (with-output-to-port cmd-out-port
  24. (λ ()
  25. (with-error-to-port err-out-port
  26. (λ ()
  27. (let* (;; Run the actual command. If an error
  28. ;; happens, it should write to the
  29. ;; err-write port. Output of the command
  30. ;; should be written to an output port,
  31. ;; which corresponds to the input-port,
  32. ;; which is returned by open-input-pipe.
  33. [in-port (open-input-pipe cmd)]
  34. ;; Read in block mode.
  35. [_ignored (setvbuf in-port 'block)])
  36. ;; Write to caller given command output port.
  37. (read-from-write-to in-port cmd-out-port)
  38. ;; Get the exit code of the command.
  39. (close-pipe in-port))))))))
  40. (define shell
  41. (lambda* (command)
  42. "Run a shell COMMAND. Return 3 values: (1) exit code, (2)
  43. command output, (3) error output."
  44. ;; Construct pairs of input and outout ports using
  45. ;; `pipe'. Whatever is written to the output port can
  46. ;; be read from the input port.
  47. (match-let ([(cmd-in . cmd-out) (pipe)]
  48. [(err-in . err-out) (pipe)])
  49. (let ([exit-code
  50. (run-command command
  51. ;; Write command output to the
  52. ;; out port, so that it can be
  53. ;; read from in port.
  54. #:cmd-out-port cmd-out
  55. ;; Write error output to the
  56. ;; error out port, so that it
  57. ;; can be read from the error in
  58. ;; port.
  59. #:err-out-port err-out)])
  60. ;; Do not forget to close the out port and error
  61. ;; out port.
  62. (close-port cmd-out)
  63. (close-port err-out)
  64. ;; Read the (error) output of the command and
  65. ;; return it.
  66. (let ([output-message (get-string-all cmd-in)]
  67. [error-message (get-string-all err-in)])
  68. (values exit-code
  69. output-message
  70. error-message))))))
  71. (let-values ([(code out err)
  72. (shell "echo 'bong' 1>&2")])
  73. (simple-format #t "code: ~a\n" code)
  74. (simple-format #t "out: ~a\n" out)
  75. (simple-format #t "err: ~a\n" err))
  76. (let-values ([(code out err)
  77. (shell "ls -al")])
  78. (simple-format #t "code: ~a\n" code)
  79. (simple-format #t "out: ~a\n" out)
  80. (simple-format #t "err: ~a\n" err))
  81. (let-values ([(code out err)
  82. (shell "ls -al 2>&1 && echo 'bong' 1>&2")])
  83. (simple-format #t "code: ~a\n" code)
  84. (simple-format #t "out: ~a\n" out)
  85. (simple-format #t "err: ~a\n" err))
  86. (let-values ([(code out err)
  87. (shell "lsasdasd -al")])
  88. (simple-format #t "code: ~a\n" code)
  89. (simple-format #t "out: ~a\n" out)
  90. (simple-format #t "err: ~a\n" err))