[-- Attachment #1: Type: text/plain, Size: 2065 bytes --] 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 :) -- Bonface M. K. (https://www.bonfacemunyoki.com) One Divine Emacs To Rule Them All GPG key = D4F09EB110177E03C28E2FE1F5BBAE1E0392253F [-- Attachment #2: signature.asc --] [-- Type: application/pgp-signature, Size: 869 bytes --]
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!
Kind regards,
Roel Janssen
[-- Attachment #1: Type: text/plain, Size: 4071 bytes --] Roel Janssen <roel@gnu.org> 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 [-- Attachment #2: signature.asc --] [-- Type: application/pgp-signature, Size: 1125 bytes --]
[-- Attachment #1: Type: text/plain, Size: 1231 bytes --] Hi! Roel Janssen <roel@gnu.org> writes: [...] > Having spent a day on this myself, this is the best I had come up with: > > (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))) > > I certainly hope someone can come up with a better solution! > Thanks. If I don't find anything, I'll give it a shot :) > Kind regards, > Roel Janssen > > > > > -- Bonface M. K. (https://www.bonfacemunyoki.com) One Divine Emacs To Rule Them All GPG key = D4F09EB110177E03C28E2FE1F5BBAE1E0392253F [-- Attachment #2: signature.asc --] [-- Type: application/pgp-signature, Size: 869 bytes --]