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.