[Toybox] Endless bash questions...

Ryan Prichard rprichard at google.com
Thu Jun 30 21:39:31 PDT 2022


On Mon, Jun 6, 2022 at 8:50 AM Chet Ramey <chet.ramey at case.edu> wrote:

> On 6/4/22 7:12 PM, Rob Landley wrote:
> >
> > P.S. Currently I'm trying to work out the sequencing of redirects vs
> > $(subshells) because these work:
> >
> > $ bash -c $'if true; then cat; fi << EOF\none two\nEOF'
> > one two
> > $ bash -c $'[[ $(cat) == "one two" ]] <<EOF\none two\nEOF'
> > $
> > $ bash -c $'[[ $(cat) == "one two" ]] <<EOF\none two\nEOF\n[ $? -eq 0 ]
> && echo yes'
> > yes
> >
> > But this hangs (cat is reading stdin, not the HERE document):
> > $ bash -c $'[ $(cat) == "one two" ] <<EOF\none two\nEOF'
> > ^C
>
> It's an order of operations question. One of the things about compound
> commands is that the redirections apply to the entire command, so they
> are performed before the compound command is executed. So what happens is
> the command gets parsed into a tree, like always, then executed, and
> redirections happen before the command is executed. For `[[' the operand
> expansion is part of the execution, so the redirection has already taken
> place.
>
> Now, `[' is a simple command, not a compound command. Bash performs the
> word expansions before performing redirections. It always has, and it
> makes things like handling null commands with redirections slightly
> easier. It's not strictly Posix-conformant.
>
> (And having the redirections precede the simple command on the input line
> only affects the parser -- it ends up getting parsed to the same structure
> and executed the same way as putting them after the command.)
>

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:

$ bash -c 'out=$(echo err >&2) 2>/dev/null'
err
$ zsh -c 'out=$(echo err >&2) 2>/dev/null'
$ dash -c 'out=$(echo err >&2) 2>/dev/null'
$ adb shell 'out=$(echo err >&2) 2>/dev/null'   # Android uses mksh
$ /x/toybox/toybox sh -c 'out=$(echo err >&2) 2>/dev/null'

I see the same result if I replace $(...) with `...`.

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).

Surely this syntax is POSIX-specified, but I wonder if the semantics are
specified.

-Ryan
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.landley.net/pipermail/toybox-landley.net/attachments/20220630/76690f57/attachment.htm>


More information about the Toybox mailing list