On 05-Nov-2014 at 18:00, Geoff Clare wrote via bug 888 on Austin Group
Bug Tracker:
> to:
> 
> The following examples illustrate some of the ways in which '*' and '@'
> can be expanded:
> 
> <tt>set "abc" "def ghi" "jkl"
[...]
> IFS='' # null
[...]
> unset var
> printf '%s\n' ${var-$*}
> <b>abcdef ghijkl</b>

This example has made it in the published standard by now.
Unfortunately, following discussions on the bug-bash list[*], I believe
this particular example is incorrect. This refers to C165.pdf, section
C.2.5, page 3724, lines 127689-127690.

According to the specification (2.5.2 Special Parameters), given null
IFS and unset 'var', the output of
        printf '%s\n' ${var-$*}
should be:
        abc
        def ghi
        jkl
and not
        abcdef ghijkl

Reasoning:

First, given an unset 'var', unquoted $* and unquoted ${var-$*} (and
unquoted ${1+$*}, etc) should act identically. If they don't, that's a
bug either way.

Second, the cited example is contrary to the specification, which says:
"Expands to the positional parameters, starting from one, initially
producing one field for each positional parameter that is set. When the
expansion occurs in a context where field splitting will be performed,
any empty fields may be discarded and each of the non-empty fields shall
be further split as described in Field Splitting. [...]"

Well, the expansion occurs "in a context where field splitting will be
performed" because it is unquoted (the fact that IFS happens to be null
is neither here nor there; its value or lack thereof has no bearing on
the lexical context). So the non-empty fields, having been generated,
"shall be further split as described in Field Splitting", which, given
that IFS is null, is a no-op.

In other words, quoted "$*" should join the fields into one, but (given
null IFS) unquoted $* should leave the fields alone altogether.

In other words again, unquoted $* should act identically to unquoted $@,
hence, unquoted ${var-$*}, ${1+$*}, etc. should act identically to
unquoted ${var-$@}, ${1+$@}, etc.

(Note that the case of a default assignment using a parameter
substitution, e.g. ${var=$*} given unset 'var', is different; 2.6.2
Parameter Expansion explicitly states for ${parameter:=[word]} that "in
all cases, the final value of /parameter/ shall be substituted". So the
example in lines 127695-127696 is correct.)

Situation in the wild:

For ${var-$*}, ${1+$*}, etc., every current POSIX shell except bash (as
of 3.x) acts like the specification. Bash 3.x (2007) and up act like the
buggy example (which makes me wonder if the buggy example was
accidentally inspired by bash's behaviour).

Given the test script:

IFS=
set "abc" "def ghi" "jkl"
printf '$*: '
printf '|%s| ' $*
printf '  ${1+$*}: '
printf '|%s| ' ${1+$*}

test results for some current shells are as follows:

 bash:  $*: |abc| |def ghi| |jkl|   ${1+$*}: |abcdef ghijkl|
 dash:  $*: |abc| |def ghi| |jkl|   ${1+$*}: |abc| |def ghi| |jkl|
 yash:  $*: |abc| |def ghi| |jkl|   ${1+$*}: |abc| |def ghi| |jkl|
  zsh:  $*: |abc| |def ghi| |jkl|   ${1+$*}: |abc| |def ghi| |jkl|
ksh93:  $*: |abc| |def ghi| |jkl|   ${1+$*}: |abc| |def ghi| |jkl|
 mksh:  $*: |abc| |def ghi| |jkl|   ${1+$*}: |abc| |def ghi| |jkl|
 oksh:  $*: |abc| |def ghi| |jkl|   ${1+$*}: |abc| |def ghi| |jkl|

Thanks to Chet Ramey for giving me a heads-up on this on the bug-bash
list. There, he also wrote (on 27-Feb-2017 at 21:03):

> You might also prepare a counter to the argument that at the time the
> $* on the right side of the parameter expansion is expanded, the rules
> in force are detailed in 2.6.2 ("word shall be subjected to tilde
> expansion, parameter expansion, command substitution, and arithmetic
> expansion"), and word splitting isn't listed. I think that came up before.

I've got three counterpoints to that:

1. This is irrelevant, because the bug does not concern splitting
fields, but instead failure to generate fields as specified.

2. Even if it were relevant, in the case under discussion, IFS is null,
so field splitting is a no-op anyway.

3. In the general case, field splitting not being listed there simply
means that field splitting is not performed for the word on the right
side /within/ an expansion such as ${var-$*} (in this case, that word
being $*). If neither the ${var-$*} expansion as a whole nor the /word/
within the expansion (in this case, $*) are quoted, then field splitting
is performed as normal for the expansion as a whole (as is pathname
expansion/globbing), as detailed in 2.6.

Thanks,

- M.

Reply via email to