This script was posted as answer to a Question.
And I'm trying to work out what's going on.
result=$(
{
{
ssh host app-status >&3 3>&-; echo "$?"
} | {
until read -t1 ret; do
printf . >&2
done
exit "$ret"
}
} 3>&1
)
Here's my explanation, but I'm sure it's wrong.
- The outer
{...} 3>&1
: fd 3 is opened as a duplicate of stdout - Then second half of pipe, '| { }` no redirection
- In read loop printf's stdout is duplicated with stderr, so in 2. (above) all output actually comes via stderr.
- Now the first half of pipe,
{ ssh ... } |
: stdout of ssh is dupped onto fd3 (which is in fact stdout from 1. fd 3 is closed with3>&-
so stdout is re-opened onto what it was originally and this is piped into 2. - finally,
echo
just prints to stdout
So my question (problem with understanding) is; Is the result of this the same as just printf to stderr ? What does the voodo redirect to 3 actually achieve?
Is there anything asynchronous in here ?
Best Answer
Inside
$(...)
, stdout (fd 1) is a pipe. At the other end of the pipe, the shell reads the output and stores it into the$result
variable.With:
$({ blah; } 3>&1)
we make it that both fd 3 and 1 point to that pipe inblah
.blah
iscmd1 | cmd2
. Therecmd1
andcmd2
are started concurrently withcmd1
fd 1 pointing to another pipe (the one tocmd2
), however we don't wantssh
output to go to that pipe, we want it to go to the first pipe so that it can be stored in$result
.So we have
{ ssh >&3; echo "$?"; } | cmd2
, so that only theecho
output goes to the pipe tocmd2
.ssh
output (fd 1) goes to$result
.ssh
not needing a fd 3, we close it for it after we've used it to set fd 1 (3>&-
).cmd2
's input (fd 0) is the second pipe. Nothing is writing to that pipe (sincessh
is writing to the first pipe) untilssh
terminates andecho
outputs the exit status there.So in
cmd2
(being theuntil
loop), theread -t1
is actually waiting with timeout untilssh
exits. After which,read
will return successfully with the content of$?
fed byecho
.