<div dir="ltr"><div dir="ltr">On Mon, Jun 6, 2022 at 8:50 AM Chet Ramey <<a href="mailto:chet.ramey@case.edu">chet.ramey@case.edu</a>> wrote:<br></div><div class="gmail_quote"><blockquote class="gmail_quote" style="margin:0px 0px 0px 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">On 6/4/22 7:12 PM, Rob Landley wrote:<br>
><br>
> P.S. Currently I'm trying to work out the sequencing of redirects vs<br>
> $(subshells) because these work:<br>
> <br>
> $ bash -c $'if true; then cat; fi << EOF\none two\nEOF'<br>
> one two<br>
> $ bash -c $'[[ $(cat) == "one two" ]] <<EOF\none two\nEOF'<br>
> $<br>
> $ bash -c $'[[ $(cat) == "one two" ]] <<EOF\none two\nEOF\n[ $? -eq 0 ] && echo yes'<br>
> yes<br>
> <br>
> But this hangs (cat is reading stdin, not the HERE document):<br>
> $ bash -c $'[ $(cat) == "one two" ] <<EOF\none two\nEOF'<br>
> ^C<br>
<br>
It's an order of operations question. One of the things about compound<br>
commands is that the redirections apply to the entire command, so they<br>
are performed before the compound command is executed. So what happens is<br>
the command gets parsed into a tree, like always, then executed, and<br>
redirections happen before the command is executed. For `[[' the operand<br>
expansion is part of the execution, so the redirection has already taken<br>
place.<br>
<br>
Now, `[' is a simple command, not a compound command. Bash performs the<br>
word expansions before performing redirections. It always has, and it<br>
makes things like handling null commands with redirections slightly<br>
easier. It's not strictly Posix-conformant.<br>
<br>
(And having the redirections precede the simple command on the input line<br>
only affects the parser -- it ends up getting parsed to the same structure<br>
and executed the same way as putting them after the command.)<br></blockquote><div><br></div><div>I noticed a situation where bash is behaving differently from other shells I've tested, and it looked related, maybe? If the $(...) subshell is assigned to a variable, then the redirection doesn't apply to it:</div><div><br></div><div>$ bash -c 'out=$(echo err >&2) 2>/dev/null'<br>err<br></div><div>$ zsh -c 'out=$(echo err >&2) 2>/dev/null'<br>$ dash -c 'out=$(echo err >&2) 2>/dev/null'<br></div><div>$ adb shell 'out=$(echo err >&2) 2>/dev/null'   # Android uses mksh</div><div>$ /x/toybox/toybox sh -c 'out=$(echo err >&2) 2>/dev/null'</div><div><br></div><div>I see the same result if I replace $(...) with `...`.</div><div><br></div><div>FWIW, I noticed this behavior while writing code to capture stdout and stderr separately, then print one after another. I'm not actually redirecting FD2 to /dev/null, but rather to FD1, just in case FD1 and FD2 unexpectedly point to different files/pipes. I only actually need the code on old versions of Android (prior to N, which added the shell_v2 adb feature).</div><div><br></div><div>Surely this syntax is POSIX-specified, but I wonder if the semantics are specified.</div><div><br></div><div>-Ryan</div><div><br></div></div></div>