There's open-process / close / process-status for handling the output as a port.
Using string ports you can copy the contents into a string:
(define substring-size 1024)
(define (port->string port) (define str (##make-string substring-size)) (call-with-output-string "" (lambda (out-port) (let lp () (let ((res (read-substring str 0 substring-size port))) (if (< res substring-size) (begin (##string-shrink! str res) (##write-string str out-port)) (begin (##write-string str out-port) (lp))))))))
Note that this stops reading if either end-of-file is reached or a timeout happens (in case you did set up one). Using peek-char and eof-object? you could check whether it stopped because of a timeout or eof.
(Using threads, you could capture stderr and stdout separately if process-port would be able to return separate ports for them.)
You could also slurp in the port as a stream (lazily built list), that can be beneficial if you don't want to have the whole content in memory at once, and can be more practical for working with parsing combinators, for example.
Christian.