On 23/08/2023 02:59, Greg Wooledge wrote:
bar() {
local fd
foo {fd}>&1 1>&2 2>&${fd} {fd}>&-
}
Running this appears to gives the correct results -- outputs go to the
right places -- but it leaves the temporary FD open. The final
redirection to close it doesn't work.
At first glance it is documented and effect of {fd}>&- is limited to the
function call
info "(bash) Redirections"
If {VARNAME} is supplied, the redirection persists
beyond the scope of the command, allowing the shell programmer to manage
the file descriptor's lifetime manually. The 'varredir_close' shell
option manages this behavior (*note The Shopt Builtin::).
info "(bash) The Shopt Builtin"
'varredir_close'
If set, the shell automatically closes file descriptors
assigned using the '{varname}' redirection syntax (*note
Redirections::) instead of leaving them open when the command
completes.
However the redirection does not persist if an external executable is
called instead of a BASH function. Perhaps it should be discussed with
BASH developers.
foo() {
sh -c 'echo "internal $1" /proc/self/fd/*' foo "$1"
}
bar() {
local fd
sh -c "echo 'external before' /proc/self/fd/*"
sh -c "echo 'external closed' /proc/self/fd/*" {fd}>&1 1>&2
2>&${fd} {fd}>&-
sh -c "echo 'external after ' /proc/self/fd/*"
echo "fd: $fd"
sh -c "echo 'external before' /proc/self/fd/*"
sh -c "echo 'external open ' /proc/self/fd/*" {fd}>&1 1>&2 2>&${fd}
sh -c "echo 'external after ' /proc/self/fd/*"
echo "fd: $fd"
echo
sh -c "echo 'internal before' /proc/self/fd/*"
foo "closed" {fd}>&1 1>&2 2>&${fd} {fd}>&-
sh -c "echo 'internal after ' /proc/self/fd/*"
echo "fd: $fd"
if [ -n "$fd" ]; then exec {fd}>&-; fd=; fi
sh -c "echo 'internal before' /proc/self/fd/*"
foo "open " {fd}>&1 1>&2 2>&${fd}
sh -c "echo 'internal after ' /proc/self/fd/*"
echo "fd: $fd"
if [ -n "$fd" ]; then exec {fd}>&-; fd=; fi
}
bar
Pay attention to {fd} that is is 10, other may be ignored, in particular
/proc/self/fd opened by readdir is 3, some inotify is 20 below.
external before /proc/self/fd/0 /proc/self/fd/1 /proc/self/fd/2
/proc/self/fd/20 /proc/self/fd/3
external closed /proc/self/fd/0 /proc/self/fd/1 /proc/self/fd/2
/proc/self/fd/20 /proc/self/fd/3
external after /proc/self/fd/0 /proc/self/fd/1 /proc/self/fd/2
/proc/self/fd/20 /proc/self/fd/3
fd:
external before /proc/self/fd/0 /proc/self/fd/1 /proc/self/fd/2
/proc/self/fd/20 /proc/self/fd/3
external open /proc/self/fd/0 /proc/self/fd/1 /proc/self/fd/10
/proc/self/fd/2 /proc/self/fd/20 /proc/self/fd/3
external after /proc/self/fd/0 /proc/self/fd/1 /proc/self/fd/2
/proc/self/fd/20 /proc/self/fd/3
fd:
internal before /proc/self/fd/0 /proc/self/fd/1 /proc/self/fd/2
/proc/self/fd/20 /proc/self/fd/3
internal closed /proc/self/fd/0 /proc/self/fd/1 /proc/self/fd/2
/proc/self/fd/20 /proc/self/fd/3
internal after /proc/self/fd/0 /proc/self/fd/1 /proc/self/fd/10
/proc/self/fd/2 /proc/self/fd/20 /proc/self/fd/3
fd: 10
internal before /proc/self/fd/0 /proc/self/fd/1 /proc/self/fd/2
/proc/self/fd/20 /proc/self/fd/3
internal open /proc/self/fd/0 /proc/self/fd/1 /proc/self/fd/10
/proc/self/fd/2 /proc/self/fd/20 /proc/self/fd/3
internal after /proc/self/fd/0 /proc/self/fd/1 /proc/self/fd/10
/proc/self/fd/2 /proc/self/fd/20 /proc/self/fd/3
fd: 10
GNU bash, version 5.2.15(1)-release (x86_64-pc-linux-gnu)
Greg Wooledge
bar() {
local fd rc
foo {fd}>&1 1>&2 2>&${fd}
rc=$?
exec {fd}>&-
return "$rc"
}
I have not tested if "trap" is more robust in the presence of "set -e -o
pipefail". I know, there are enough pitfalls with this options.
At this point, the "pure sh" version looks a whole lot simpler,
doesn't it?
You mentioned the limitation: a spare file descriptor must be known.