[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: Shell commands with output to string
From: |
Josselin Poiret |
Subject: |
Re: Shell commands with output to string |
Date: |
Wed, 09 Mar 2022 15:14:21 +0100 |
Hello Zelphir,
Zelphir Kaltstahl <zelphirkaltstahl@posteo.de> writes:
> I have questions regarding this workaround:
>
> Can you explain how and why this works? I have tried to make sense of it and
> here are my notes so far (reference:
> https://notabug.org/ZelphirKaltstahl/guile-examples/src/2dead9f7bb9b40fc26eb490a93e1dc7abca7252c/shell/system-asterisk-stdout-to-stderr-redirection-bug.scm):
Note that here, I used undocumented behavior of open-pipe*, which can be
understood by inspecting libguile/posix.c (look for piped-process) and
module/ice-9/popen.scm (look for open-pipe*).
> ~~~~
> (match-let (((input . output) (pipe)))
> ;; Hack to work around Guile bug 52835 -- How does
> ;; duplicating the port help? From the docs: "Returns a
> ;; new port which is opened on a duplicate of the file
> ;; descriptor underlying port, with mode string modes as
> ;; for open-file. The two ports will share a file position
> ;; and file status flags. [...]"
> (define dup-output (duplicate-port output "w"))
The above Guile bug occurs because the current output and error ports
point to the same file descriptor. Using duplicate-port makes sure that
we get a port with a duplicated file descriptor!
> ;; Void pipe, but holds the pid for close-pipe.
> (define dummy-pipe
> ;; Set current-input-port to /dev/null. -- What will be
> ;; read from there? Nothing?
> (with-input-from-file "/dev/null"
Yes, for our use-case we don't need to feed anything to the command, but
it's always possible to hook this up to a pipe if you need to.
> (lambda ()
> ;; Set the current-output-port to the one created
> ;; above using (pipe).
> (with-output-to-port output
> (lambda ()
> ;; Set the error port to the duplicated output
> ;; port. This might be the redirection of stderr
> ;; to stdout.
> (with-error-to-port dup-output
Exactly, this is the redirection.
> (lambda ()
> ;; Run open-file*, but why is there an empty
> ;; string prepended to command? Perhaps to
> ;; allow using either a list or a string as
> ;; a command?
> (apply open-pipe* (cons "" command)))))))))
Here's the undefined behavior, the first argument of open-pipe* is a
mode for the pipe it opens, but here we don't want it to open any pipes,
all our default ports are setup so that start_child will set the child's
stdin/out/err to their file descriptors.
> (close-port output)
> (close-port dup-output)
> (handler input)
> (close-port input)
> (close-pipe dummy-pipe))
> ~~~~
>
> My other question is: Do I still need this workaround, if I use the
> following,
> to run commands? And if so, why? In which cases would my code not do the
> right
> thing? (reference:
> https://notabug.org/ZelphirKaltstahl/guile-examples/src/2dead9f7bb9b40fc26eb490a93e1dc7abca7252c/shell/example-03-using-popen-get-out-and-error.scm):
Looking briefly at your code, I don't think that bug could be affecting
you. You can have an issue if you're trying to redirect a standard fd
to another standard fd, but if you're using fresh ports it should be ok.
Best,
--
Josselin Poiret