Roel Janssen writes: > On Thu, 2020-09-10 at 04:14 +0300, Bonface M. K. wrote: >> Hi all. Is there a way to "record" the output from both *stderr* and >> *stdout* from a guile process if you wrap it around a "system" call >> to a >> string? Here's something that works. It's not /exactly/ what I want >> because "open-input-pipe" runs the command in a subprocess. >> >> --8<---------------cut here---------------start------------->8--- >> (define (run-job job) >> (let* ((port (open-input-pipe job)) >> (str (read-line port))) >> (close-pipe port) >> str)) >> >> (display (format #t "~s ~s ~s" >> "padding" >> (run-job "echo hello") >> "testing")) >> --8<---------------cut here---------------end--------------->8--- >> >> I've tried out creating a fork: >> >> --8<---------------cut here---------------start------------->8--- >> (define (run-job thunk) >> (call-with-output-string >> (λ (port) >> (match (pipe) >> ((in . out) >> (match (primitive-fork) >> (0 ; child >> (close in) >> (with-error-to-port out thunk)) >> ((= waitpid (pid . exit-code)) ;; parent >> (close out) >> (display (read-line in) port)))))))) >> >> ;; Doesn't work: >> (display (format #t "~s ~s ~s" >> "padding" >> (run-job (system "echo hello")) >> "testing")) >> --8<---------------cut here---------------end--------------->8--- >> >> Ideally for a correct output without errors, I'd like to have as >> output: >> >> --8<---------------cut here---------------start------------->8--- >> "padding" "hello" "testing" >> --8<---------------cut here---------------end--------------->8--- >> >> and in the event I have an error, like say, by running (system >> "echoooo hello"), I get >> the output: >> >> --8<---------------cut here---------------start------------->8--- >> "padding" "sh: command not found" "testing"" >> --8<---------------cut here---------------end--------------->8--- >> >> PS: I'm new to Guile :) >> > > Having spent a day on this myself, this is the best I had come up with: > > --8<---------------cut here---------------start------------->8--- > (define (virtuoso-isql-query query) > "Executes QUERY via ISQL and returns a both an ERROR-PORT and a PORT > to read CSV output from." > (let* ((tmp (getenv "TMPDIR")) > (error-port (mkstemp! (string-append (if tmp tmp "/tmp") "/sg- > XXXXXX"))) > (port (open-input-pipe > (format #f "~a ~a -U ~a -P ~a verbose=off > csv_rfc4180=on csv_rfc4180_field_separator=, exec='~:a' 2> ~a" > (isql-bin) (isql-port) (rdf-store- > username) > (rdf-store-password) > (string-append "SPARQL " query) > (port-filename error-port))))) > (setvbuf port 'block 4096) > (values error-port port))) > --8<---------------cut here---------------end--------------->8--- > I certainly hope someone can come up with a better solution! I’m not sure whether it’s better, but this is the solution I found: (import (ice-9 rdelim) (ice-9 popen) (rnrs io ports)) (define (call-command-with-output-error-to-string cmd) (let* ((err-cons (pipe)) (port (with-error-to-port (cdr err-cons) (λ() (open-input-pipe cmd)))) (_ (setvbuf (car err-cons) 'block (* 1024 1024 16))) (result (read-delimited "" port))) (close-port (cdr err-cons)) (values result (read-delimited "" (car err-cons))))) (call-command-with-output-error-to-string "echo 1; echo 2 >&2") Also available on my website: https://www.draketo.de/software/guile-capture-stdout-stderr.html Best wishes, Arne -- Unpolitisch sein heißt politisch sein ohne es zu merken