[Toybox] And again.

Chet Ramey chet.ramey at case.edu
Tue Sep 1 07:19:39 PDT 2020

On 8/28/20 2:28 AM, Rob Landley wrote:
> I'm trying hard not to bother you anymore, but I think the bash man page is
> wrong. It says says:
>        case word in [ [(] pattern [ | pattern ] ... ) list ;; ] ... esac
>               A case command first expands word, and tries to match it against
>               each pattern in turn, using the same matching rules as for path‐
>               name  expansion  (see  Pathname  Expansion  below).  The word is
>               expanded using tilde expansion, parameter  and  variable  expan‐
>               sion,  arithmetic  expansion, command substitution, process sub‐
>               stitution and quote removal.  Each pattern examined is  expanded
>               using  tilde expansion, parameter and variable expansion, arith‐
>               metic expansion, command substitution, and process substitution.
> And I have questions:
> 1) Bash DOES remove quotes from the pattern, it has to because splitting is
> disabled so spaces and $IFS can get inserted:

It doesn't perform quote removal, and Posix says it should not. What it
does do is make sure that the quote characters arrange to quote parts of
the pattern appropriately so that special matching characters match
themselves. The shell has to remember which parts of the pattern were
quoted, and make sure that those quoted characters get passed to the
matcher (which may or may not be fnmatch()) in whatever way the matcher
requires. That usually means prefixing them with a backslash, but then
you get into what happens with quoted characters inside bracket
expressions. The word expansions still happen how they're supposed to.

There was a ferocious argument about this a couple of years ago, and there
are still arguments about how to specify quoting in shell pattern matching.

If you were to perform quote removal on the patterns, you'd need something

case "$x" in \\*) echo 'literal asterisk' ;; esac

to match an asterisk.

> 2) process substitution? Really? Under what circumstances does:
>   case <(potato) in $PATTERN) echo hello;; esac
> trigger usefully? 

If people want to do dumb shit, people are going to do dumb shit. One
could use this to determine whether bash uses /dev/fd or named pipes for
process substitution, but you shouldn't really have to care.

> My code is treating <() as a form of redirection, so it's handled by
> expand_redir() rather than expand_arg_nobrace(), and moving it is problematic
> because only one context has the filehandle tracking (I.E. recording what to
> close again afterwards).

That's probably going to come back and bite you, since process substitution
is a word expansion.

> 3) $(case a in a); echo hello; esac) is not something my parsing can handle (it
> just counts quotes and parentheses, it's not parsing flow control statements
> inside what is essentially a nested quoting context), and I would have to rip
> out SO much stuff to make it do so I think I'm ok with not supporting that for
> the moment. And technically you can do $(case a in (a); echo hello; esac) and
> that does work.

This will certainly come back and bite you.

Bash used to do it this way, but Posix says that any arbitrary shell script
can appear in $() command substitution, so I got a bunch of bug reports.

I ended up having to write special-case code for this, because bison/yacc
can't easily handle calling the parser recursively.

``The lyf so short, the craft so long to lerne.'' - Chaucer
		 ``Ars longa, vita brevis'' - Hippocrates
Chet Ramey, UTech, CWRU    chet at case.edu    http://tiswww.cwru.edu/~chet/

More information about the Toybox mailing list