Discussion:
clarification on $*/$@
Stephane Chazelas
2014-10-20 21:54:20 UTC
Permalink
Hello.

Apologies if that has already been discussed before. I seem to
recall it has, but can't find any reference now (I can find a
number of usenet discussions on it though).

At
http://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#tag_18_05_02
2.5.2 Special Parameters
Listed below are the special parameters and the values to
which they shall expand. Only the values of the special
parameters are listed; see wordexp for a detailed summary of
all the stages involved in expanding words.
@
Expands to the positional parameters, starting from
one.
What does "expands to the positional parameters" mean? POSIX sh
have no arrays, and variables like $@ or or any other variable
can be referenced in context where only one value is accepted.

Does it mean the concatenation of all positional parameters
starting with $1 (what is meant by "one"?)? How are they
concatenated? (note that $0 is not considered a positional
parameter in the spec text AFAICT so the "starting from one" is
redundant).
When the expansion occurs within double-quotes,
and where field splitting (see Field Splitting) is
performed,
The reference to "Field Splitting" is confusing here given that
"Field Splitting" is not performed within double quotes. The
link doesn't clearly state *where* field splitting is performed.
each positional parameter shall expand as
a separate field, with the provision that the
expansion of the first parameter shall still be
joined with the beginning part of the original word
(assuming that the expanded parameter was embedded
within a word), and the expansion of the last
parameter shall still be joined with the last part of
the original word. If there are no positional
*
Expands to the positional parameters, starting from
one. When the expansion occurs within a double-quoted
string (see Double-Quotes), it shall expand to a
single field with the value of each parameter
separated by the first character of the IFS variable,
or by a <space> if IFS is unset. If IFS is set to a
null string, this is not equivalent to unsetting it;
its first character does not exist, so the parameter
values are concatenated.
We can kind of guess what is meant when $@ and $* are quoted in
list contexts, but not otherwise.

In the Bourne shell, $@ and $* were the same and were variables
whose content was the concatenation of the positional
parameters.

The only thing special was "$@" ($@ quoted) in list contexts
(like in arguments to simple commands or in for i in "$@").

So in:

set a ***@c
IFS=:,@
printf '<%s>\n' $*

$* expands to "a:***@c" and undergoes word splitting.

set a ***@c
IFS=
printf '<%s>\n' $@

$@ expands to one argument only: "a ***@c"


ksh introduced the joining on the joining on the first character
of IFS instead of a space character and arrays. $* and $@ still
seem to contain the concatenation of the positional parameters
with the first character of IFS except that in list contexts,
unquoted $* and $@ are also split on the positional parameters

set a b
IFS=
a=$@

assigns "ab" to $a, but

set a b
IFS=
printf '<%s>\n' $@

expands to 2 arguments "a" and "b".

yash ash only does the concatenation with the first character of
IFS (or at least did until that change in dash:
http://thread.gmane.org/gmane.comp.shells.dash/999)

So:

IFS=
set a b
printf '<%s>\n' $@

would expand to one "ab" argument as you'd expect (as a logical
continuation of the Bourne shell and to be consistent with
a=$@ and from a shell that doesn't support arrays).

bash behaviour is rather odd. In some places $@ and $* seem to
be the concatenation of arguments with the first character of
IFS, sometimes with space.

$ bash -c 'set a b; IFS=; a="$@"; echo "$a"'
a b
$ bash -c 'set a b; IFS=; a=$*; echo "$a"'
ab
$ bash -c 'set a b; IFS=; a="a bc"; echo ${a#$*}'
c

As discussed at

http://thread.gmane.org/gmane.linux.debian.devel.general/197901
and
https://bugs.launchpad.net/mksh/+bug/1381993

There is some variation among shells when $@ and $* are used
unquoted and/or in non-list contexts. Including bugs in mksh and
ksh93

I think a better wording could be that $@ and $* contain the
concatenation of the positional parameters separated with the
first character (actually it's "byte" in ksh93/mksh/zsh/dash by
the way) of IFS (or nothing if IFS is empty or space if IFS is
unset), with the current wording for "$@" in list context and
the behaviour unspecified if $* and $@ are unquoted in list
context (${var#$*} not qualifying as a list context).
--
Stephane
Geoff Clare
2014-10-22 10:14:16 UTC
Permalink
Post by Stephane Chazelas
Apologies if that has already been discussed before. I seem to
recall it has, but can't find any reference now (I can find a
number of usenet discussions on it though).
The only previous discussion I can find is from Oct 2008.

http://thread.gmane.org/gmane.comp.standards.posix.austin.general/74
Post by Stephane Chazelas
2.5.2 Special Parameters
Listed below are the special parameters and the values to
which they shall expand. Only the values of the special
parameters are listed; see wordexp for a detailed summary of
all the stages involved in expanding words.
@
Expands to the positional parameters, starting from
one.
What does "expands to the positional parameters" mean? POSIX sh
can be referenced in context where only one value is accepted.
Does it mean the concatenation of all positional parameters
starting with $1 (what is meant by "one"?)? How are they
concatenated? (note that $0 is not considered a positional
parameter in the spec text AFAICT so the "starting from one" is
redundant).
When field splitting is performed, it expands to separate fields.
When field splitting is not performed, e.g. var=$@, the behaviour
is unspecified.
Post by Stephane Chazelas
When the expansion occurs within double-quotes,
and where field splitting (see Field Splitting) is
performed,
The reference to "Field Splitting" is confusing here given that
"Field Splitting" is not performed within double quotes.
Good point. I think it is reasonably clear what is intended, but to
make it clearer we should probably change the end of 2.6.5 Field
Splitting para 1 to say:

... the shell shall scan the results of expansions and substitutions
that did not occur in double-quotes, and the results of expansions
of the special parameter '@' in double-quotes, for field splitting
and multiple fields can result.
Post by Stephane Chazelas
The
link doesn't clearly state *where* field splitting is performed.
True - each part of the language description that says expansions are
performed says which expansions apply. E.g. 2.9.1 Simple Commands step 4
says "Each variable assignment shall be expanded for tilde expansion,
parameter expansion, command substitution, arithmetic expansion, and
quote removal prior to assigning the value". Since field splitting is
not listed, it is not performed for variable assignments.

[...]
Post by Stephane Chazelas
concatenation of the positional parameters separated with the
first character (actually it's "byte" in ksh93/mksh/zsh/dash by
the way) of IFS (or nothing if IFS is empty or space if IFS is
context (${var#$*} not qualifying as a list context).
There is certainly room for improvement in this area, although given the
wide variation in existing practice, if we make changes we will need to
be careful not to accidentally disallow some existing behaviours.
--
Geoff Clare <g.clare-7882/***@public.gmane.org>
The Open Group, Apex Plaza, Forbury Road, Reading, RG1 1AX, England
Stephane Chazelas
2014-10-22 10:54:22 UTC
Permalink
2014-10-22 11:14:16 +0100, Geoff Clare:
[...]
Post by Geoff Clare
When field splitting is performed, it expands to separate fields.
[...]

Thanks.

Do you mean it expands into separate fields as part of the
normal word splitting process as in the Bourne, Almquist or yash
shells:

unset IFS
set a b "c d"
rm $*

would remove the 4 files a, b, c, d. and:

IFS=
set a b "c d"
rm $*

would remove the one file "abc d"? ("a b c d" in the Bourne
shell).

Or $*/$@ treated as some sort of array and then subject to word
splitting as in ksh, bash, zsh (in sh emulation)

IFS=
set a b "c d"
rm $*

would remove 3 files a, b and "c d"

Or just some form of array where the splitting into arguments
replaces the normal word splitting on IFS (only zsh has an
approaching behaviour (empty elements are removed)).

unset IFS
set a b "c d"
rm $*

would remove 3 files a, b and "c d"?


It's not clear to me what behaviour the description mandates
(the 3rd one implemented in *no* shell is the one that sounds
more like it) and there's variation accross implementations.

Is ${foo#"$*"} specified? What about "${foo#$*}" "${foo-$*}" (is
$* considered as being inside quotes there)? What about the common
${1+"$@"} or "${1+$@}" or ${foo:="$@"}...?

What should be the output in:

IFS=?
set a c
foo=abcd
echo ${foo#"$*"}
echo "${foo#$*}"

bash gives

abcd
abcd

ksh93 gives

d
d

All other shells give

abcd
d
--
Stephane
Stephane Chazelas
2014-10-22 11:33:21 UTC
Permalink
2014-10-22 11:54:21 +0100, Stephane Chazelas:
[...]
Post by Stephane Chazelas
Is ${foo#"$*"} specified? What about "${foo#$*}" "${foo-$*}" (is
$* considered as being inside quotes there)?
Answering my own question here. Sorry, I should have checked
earlier.

http://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#tag_18_06_02
has

} Enclosing the full parameter expansion string in double-quotes
} shall not cause the following four varieties of pattern
} characters to be quoted, whereas quoting characters within the
} braces shall have this effect. In each variety, if word is
} omitted, the empty pattern shall be used

So "${foo#$*}" is unspecified and ${foo#"$*"} is specified so
the output of
Post by Stephane Chazelas
IFS=?
set a c
foo=abcd
echo ${foo#"$*"}
echo "${foo#$*}"
Should be:

abcd
<unspecified>

and ksh93 has a bug I'd say.

That means btw that "${foo#~}" would work like "${foo#$HOME}"
but that's not useful as you want "${foo#"$HOME"}" here.
Still not sure about those though.
--
Stephane
Geoff Clare
2014-10-22 15:03:57 UTC
Permalink
Post by Stephane Chazelas
[...]
Post by Geoff Clare
When field splitting is performed, it expands to separate fields.
[...]
Thanks.
Do you mean it expands into separate fields as part of the
normal word splitting process as in the Bourne, Almquist or yash
unset IFS
set a b "c d"
rm $*
IFS=
set a b "c d"
rm $*
would remove the one file "abc d"? ("a b c d" in the Bourne
shell).
No.
Post by Stephane Chazelas
splitting as in ksh, bash, zsh (in sh emulation)
IFS=
set a b "c d"
rm $*
would remove 3 files a, b and "c d"
Yes.
Post by Stephane Chazelas
Or just some form of array where the splitting into arguments
replaces the normal word splitting on IFS (only zsh has an
approaching behaviour (empty elements are removed)).
unset IFS
set a b "c d"
rm $*
would remove 3 files a, b and "c d"?
No.
Post by Stephane Chazelas
It's not clear to me what behaviour the description mandates
(the 3rd one implemented in *no* shell is the one that sounds
more like it) and there's variation accross implementations.
My reading of the standard is that for $@, and for $* when not in
double-quotes, the parameter expansion itself produces multiple
fields. If not double-quoted, field splitting using IFS is then
applied to the results of the parameter expansion.

I can see that 2.5.2 is not particularly clear on this. It's mainly
based on the part of the @ description that says "When the expansion
occurs within double-quotes, [...], each positional parameter shall
expand as a separate field". I read that as if there was a "still" in
the middle of "shall expand". I.e. the earlier text "Expands to the
positional parameters" already implies expansion to multiple fields,
and this part is saying that you still get multiple fields when the $@
is in double-quotes.

Also, 2.6.5 Field Splitting only describes the use of IFS to split the
"results of expansions and substitutions". It does not say anything
about how "$@" produces multiple fields when IFS is empty, so that
must have happened already; it is not part of field splitting proper.

While looking into this I noticed that 2.6.2 Parameter Expansions says:

If a parameter expansion occurs inside double-quotes:

[...]

Field splitting shall not be performed on the results of the
expansion, with the exception of '@'; see Special Parameters.

This exception is clearly incorrect, as it would imply that field
splitting using IFS is done on the results of expanding $@ in
double-quotes.

It also means I went in the wrong direction in my previous post.
Instead of changing 2.6.5 Field Splitting to say that it applies to
$@ in double-quotes, we should fix the description of $@ by
changing:

When the expansion occurs within double-quotes, and where field
splitting (see Field Splitting) is performed, ...

to something like:

When the expansion occurs within double-quotes, and where field
splitting (see Field Splitting) would be performed if the
expansion was not within double-quotes, ...
Post by Stephane Chazelas
[...]
Post by Geoff Clare
Is ${foo#"$*"} specified? What about "${foo#$*}" "${foo-$*}" (is
$* considered as being inside quotes there)?
Answering my own question here. Sorry, I should have checked
earlier.
http://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#tag_18_06_02
has
} Enclosing the full parameter expansion string in double-quotes
} shall not cause the following four varieties of pattern
} characters to be quoted, whereas quoting characters within the
} braces shall have this effect. In each variety, if word is
} omitted, the empty pattern shall be used
So "${foo#$*}" is unspecified and ${foo#"$*"} is specified so
the output of
Post by Geoff Clare
IFS=?
set a c
foo=abcd
echo ${foo#"$*"}
echo "${foo#$*}"
abcd
<unspecified>
and ksh93 has a bug I'd say.
I agree. The expansion of ${foo#"$*"} should come out the same as the
expansion of ${foo#"a?c"}. The '?' is quoted and so is not special.
Post by Stephane Chazelas
That means btw that "${foo#~}" would work like "${foo#$HOME}"
but that's not useful as you want "${foo#"$HOME"}" here.
Still not sure about those though.
The first two seem clear to me: if $1 is set, they both expand to the
same thing as "$@"; if $1 is unset, the first expands to nothing and
the second expands to an empty string.

I think the third is unspecified if foo is unset, since it amounts
to doing foo="$@" which is unspecified.
--
Geoff Clare <g.clare-7882/***@public.gmane.org>
The Open Group, Apex Plaza, Forbury Road, Reading, RG1 1AX, England
Geoff Clare
2014-10-23 10:08:16 UTC
Permalink
Post by Geoff Clare
double-quotes, the parameter expansion itself produces multiple
fields. If not double-quoted, field splitting using IFS is then
applied to the results of the parameter expansion.
I can see that 2.5.2 is not particularly clear on this. [...]
Here is what I would like to see in 2.5.2 for Issue 8. It's an attempt
to state clearly what I think was the original intent (or close to it)
while minimising unspecified behaviour. What we can do in TC2 will
depend on how much existing practice in various shells differs from
this, and whether we consider their behaviour should be allowed or is
just a bug. (I would say that using the first byte of IFS, instead
of the first character, is definitely a bug.)

Note that although this is stated in terms of initially generating
separate fields and then (except for "$@") either applying field
splitting or joining them, there is no requirement for the internal
implementation details to match this description, provided the end
result is the same. I just felt it was easier and more consistent to
describe all of the expansions this way.

@ 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 shall be discarded and each of the
remaining fields shall be further split as described in [xref to
2.6.5 Field Splitting]. When the expansion occurs within
double-quotes, and where field splitting as described in [xref to
2.6.5 Field Splitting] would be performed if the expansion was not
within double-quotes (regardless of whether field splitting would
have any effect, for example if IFS is null), the initial fields
shall be retained as separate fields except that, if the parameter
being expanded was embedded within a word, the first field shall
be joined with the beginning part of the original word and the
last field shall be joined with the end part of the original word.
In all other contexts the initial fields shall be joined to form a
single field in an unspecified manner. If there are no positional
parameters, the expansion of '@' shall generate zero fields, even
when '@' is within double-quotes.

* 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 shall be discarded and each of the
remaining fields shall be further split as described in [xref to
2.6.5 Field Splitting]. When the expansion occurs in a context
where field splitting will not be performed, the initial fields
shall be joined to form a single field with the value of each
parameter separated by the first character of the IFS variable, or
separated by a <space> if IFS is unset, or with no separation if
IFS is set to a null string.

As I said before, we also need to delete the exception from this
part of 2.6.2 Parameter Expansions:

If a parameter expansion occurs inside double-quotes:

[...]

Field splitting shall not be performed on the results of the
expansion, with the exception of '@'; see Special Parameters.
--
Geoff Clare <g.clare-7882/***@public.gmane.org>
The Open Group, Apex Plaza, Forbury Road, Reading, RG1 1AX, England
Stephane Chazelas
2014-10-23 10:34:44 UTC
Permalink
2014-10-23 11:08:16 +0100, Geoff Clare:
[...]
Post by Geoff Clare
@ 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 shall be discarded and each of the
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
[...]

That breaks mksh/pdksh, but I suppose that's OK as it's the only
odd one out AFAICT.

Other than that, I think your suggestion is reasonable.

That means yash and BSD shs need to be modified (dash has
already done it, not released yet) to make sure $@ $* expand to
separate arguments in list contexts even when IFS is empty
(field splitting disabled).

bash and ksh93 need to fix their various bugs in corner cases
mentioned here.

dash/BSD sh, mksh, ksh93 should be fixed so as to join on the
first character instead of byte.


However, I liked the idea of leaving the whole behaviour
unspecified to deter people from using them as using them is
clearly wrong in most cases.

For instance, I see a number of things like

rm $*

or

rm $@

When the author actually means:

rm -- "$@"


rm -- $*

only works in zsh (not in sh emulation) or in other shells
(except ash/yash) only after set -f; IFS= (and even then it
removes the empty arguments, which for rm is just as well but in
the general case is not what you want).
--
Stephane
Schwarz, Konrad
2014-10-23 13:29:24 UTC
Permalink
-----Original Message-----
However, I liked the idea of leaving the whole behaviour unspecified to
deter people from using them as using them is clearly wrong in most
cases.
I concur. The value of specifying all these obscure corner cases is limited, since no one will be able to remember the rules in practice anyway.
Stephane Chazelas
2014-10-23 11:31:26 UTC
Permalink
2014-10-23 11:08:16 +0100, Geoff Clare:
[...]
Post by Geoff Clare
Here is what I would like to see in 2.5.2 for Issue 8.
[...]

You may also want to add that the behaviour for ${foo=$@},
${foo="$@"}, ${foo="$@"}, "${foo="$@"}" and ${foo=$*} in list
contexts (and the variant with ${foo:=...}) are unspecified as
there's no really sensible thing to do here and implementations
may for instance want to use that to assign array variables.

I'm not sure we have "${foo-$@}", "${foo-"$@"}", "${foo-$*}"
fully covered either.
--
Stephane
Chet Ramey
2014-10-22 19:52:29 UTC
Permalink
Post by Stephane Chazelas
whose content was the concatenation of the positional
parameters.
printf '<%s>\n' $*
Not really, if you meant how the historical Bourne shell behaved. The
Bourne shell expands it to "a ***@c" and performs word splitting, resulting
in

<a b><c>
Post by Stephane Chazelas
IFS=
Yes, this is what the Bourne shell did/does.
Post by Stephane Chazelas
ksh introduced the joining on the joining on the first character
seem to contain the concatenation of the positional parameters
with the first character of IFS except that in list contexts,
set a b
IFS=
assigns "ab" to $a, but
That's not true: sh, ksh, bash, and so on assign "a b". If you meant to
use $*, you're correct. Only $* is specified to use the first character
of $IFS.

If this is central to your argument, you might want to reframe it.
Post by Stephane Chazelas
set a b
IFS=
expands to 2 arguments "a" and "b".
Yes, ksh/mksh and bash do this. The historical Bourne shell expands it to
one argument: "a b".
Post by Stephane Chazelas
IFS=
set a b
would expand to one "ab" argument as you'd expect (as a logical
continuation of the Bourne shell and to be consistent with
One wouldn't. Only dash does this.
Post by Stephane Chazelas
be the concatenation of arguments with the first character of
IFS, sometimes with space.
a b
$ bash -c 'set a b; IFS=; a=$*; echo "$a"'
ab
$ bash -c 'set a b; IFS=; a="a bc"; echo ${a#$*}'
c
Yes, the third case is a problem. The other two cases are consistent with
ksh93, mksh, and other Posix shells except dash.

Chet
--
``The lyf so short, the craft so long to lerne.'' - Chaucer
``Ars longa, vita brevis'' - Hippocrates
Chet Ramey, ITS, CWRU chet-***@public.gmane.org http://cnswww.cns.cwru.edu/~chet/
Stephane Chazelas
2014-10-22 20:27:49 UTC
Permalink
Post by Chet Ramey
Post by Stephane Chazelas
whose content was the concatenation of the positional
parameters.
printf '<%s>\n' $*
Not really, if you meant how the historical Bourne shell behaved. The
in
<a b><c>
Yes, sorry, typo. I clarified later that ksh introduced the
joining on the first character of IFS instead of space.

[...]
Post by Chet Ramey
Post by Stephane Chazelas
ksh introduced the joining on the joining on the first character
seem to contain the concatenation of the positional parameters
with the first character of IFS except that in list contexts,
set a b
IFS=
assigns "ab" to $a, but
That's not true: sh, ksh, bash, and so on assign "a b". If you meant to
use $*, you're correct. Only $* is specified to use the first character
of $IFS.
You're right that a=$@ expands to "a b" when IFS is unset for
the AT&T and PD implementations of ksh (not the zsh one, not
mksh R46 at least that seems to have a bug there), but
otherwise:

set a b; IFS=:; a=$@; echo "$a"

expands to "a:b" in all of pdksh, mksh, zsh, ash, dash, yash

The only exceptions are AT&T ksh and bash.

(I was wrong to imply that ksh introduced $@ being the
concatenation of the positional parameters with the first
character of IFS though).

[...]
Post by Chet Ramey
Post by Stephane Chazelas
IFS=
set a b
would expand to one "ab" argument as you'd expect (as a logical
continuation of the Bourne shell and to be consistent with
One wouldn't. Only dash does this.
And yash and the sh of most BSDs. All the POSIX shells that
don't support arrays.
--
Stephane
Chet Ramey
2014-10-23 02:22:54 UTC
Permalink
Post by Stephane Chazelas
but
expands to "a:b" in all of pdksh, mksh, zsh, ash, dash, yash
The only exceptions are AT&T ksh and bash.
Well, and the original Bourne shell.

It looks like we'll have to leave unquoted $@ in a context where
field splitting isn't performed as undefined behavior, since there
is variation in behavior.
Post by Stephane Chazelas
Post by Chet Ramey
Post by Stephane Chazelas
IFS=
set a b
would expand to one "ab" argument as you'd expect (as a logical
continuation of the Bourne shell and to be consistent with
One wouldn't. Only dash does this.
And yash and the sh of most BSDs. All the POSIX shells that
don't support arrays.
I'd expect the BSDs' sh and dash to behave the same; they're basically the
same shell and probably haven't diverged in this area.

I'd like to hear from the yash developer on this. He's pretty much
isolated from the austin-group community, which means he doesn't have
any context other than the standard itself.

Since there's nothing in the standard that says to concatenate the
positional parameters in the expansion of an unquoted $@ in a context
where field splitting is not performed (whew!), I'd be interested in where
the notion came from.

Chet
--
``The lyf so short, the craft so long to lerne.'' - Chaucer
``Ars longa, vita brevis'' - Hippocrates
Chet Ramey, ITS, CWRU chet-***@public.gmane.org http://cnswww.cns.cwru.edu/~chet/
Stephane Chazelas
2014-10-23 09:09:27 UTC
Permalink
Post by Chet Ramey
Post by Stephane Chazelas
but
expands to "a:b" in all of pdksh, mksh, zsh, ash, dash, yash
The only exceptions are AT&T ksh and bash.
Well, and the original Bourne shell.
Yes, except that in the Bourne shell, as you said yourself,
arguments are joined with space instead of the first character
of $IFS.
Post by Chet Ramey
field splitting isn't performed as undefined behavior, since there
is variation in behavior.
The only thing that is /clearly/ specified by POSIX at the
moment and that is consistent accross all shells is "$*" (quoted
$* whatever the context) and "$@" in list contexts (though what
qualifies as a list context is not clearly specified like in
things like ${foo="$@"}).

Outside of that, the spec is unclear and shells have different
behaviour. I'd also argue it doesn't make sense to use $@ or $*
unquoted(1), or $@ in scalar context. So I would find it best if
POSIX left the behaviour unspecified.

Changing the text to match more clearly Geoff's interpretation
would force shells like yash or dash (dash is already doing it
which is what prompted me to raise the issue here) to make their
behaviour less consistent.


[...]
Post by Chet Ramey
I'd like to hear from the yash developer on this. He's pretty much
isolated from the austin-group community, which means he doesn't have
any context other than the standard itself.
Since there's nothing in the standard that says to concatenate the
where field splitting is not performed (whew!), I'd be interested in where
the notion came from.
[...]

IMO, that's the most consistent behaviour and the simplest and
most obvious thing to do for shells that don't implement array.

IMO, from the most consistent to the least, we have (describing
the (supposed) intent, ignoring the bugs in corner cases):

dash and other ash derivatives, yash:

$* and $@ are the concatenation of the positional parameters
with the first character of IFS (nothing if IFS is empty,
space if unset). And only "$@" (quoted $@) in list context
expands to the arguments. You can't make any simpler than
that, and that's all you need. And that's just like in the
Bourne shell (the only difference being 1st character of IFS
vs space).

zsh (sh emulation) and next dash.

In scalar context, $* and $@, quoted or not, are the
concatenation of the positional parameters with the first
character of IFS (nothing if IFS is empty, space if unset).

In list context, $* and $@ unquoted expand to the positional
parameters with the empty ones removed and further subject to
word splitting and globbing (only in sh emulation).

"$@" in list context expands to the positional parameters
(empty ones not removed) and "$*" is like in scalar context.

bash

In scalar context, $* and $@, quoted or not, are the
concatenation of the positional parameters with the first
character of IFS (nothing if IFS is empty, space if unset)
for $* and space for $@.

Not sure why a space for $@, but as long as it's documented,
I can't see an issue with that, and that can be justified as
being for compatibility with the Bourne shell.

In list context, $* and $@ unquoted expand to the positional
parameters with the empty ones removed and further subject to
word splitting and globbing.

"$@" in list context expands to the positional parameters
(empty ones not removed) and "$*" is like in scalar context.

pdksh/mksh

In scalar context, $* and $@, quoted or not, are the
concatenation of the positional parameters with the first
character of IFS or space if unset. If IFS is empty however,
$* is joined with nothing and $@ with space (I can't explain
why the difference here).

In list context, $* and $@ unquoted expand to the positional
parameters with the empty ones *not* removed and further
subject to word splitting and globbing.

"$@" in list context expands to the positional parameters
(empty ones not removed) and "$*" is like in scalar context.

AT&T ksh

same as pdksh except that empty positional parameters are
removed in $* and $@ (wether that's more or less consistent
than pdksh I'm undecided about).


(and BTW, if POSIX is to /clearly/ specify how $* and $@ should
be expanded in list contexts, then wether empty arguments are
removed or not should be specified as well).

Footnote:

(1) Well, there's the: case $var in $*) vs case $var in "$*") or
${var#$*} vs ${var#"$*") where the quotes double as excaping the
pattern matching operators, but that's easily worked around by
using an intermediary variable: pattern="$*"; case $var in
$pattern).
Joerg Schilling
2014-10-23 09:36:38 UTC
Permalink
Post by Stephane Chazelas
AT&T ksh
same as pdksh except that empty positional parameters are
than pdksh I'm undecided about).
Could you be more specific?

What do you understand by "AT&T ksh"?

There are:

- ksh (early versions)

- ksh88 (which seems to be ased as the base for SVr4)

- ksh88-POSIX (e.g. available on various Solaris versions),
this version identifies itself as:
"ksh88 Version (..-)11/16/88i (posix octal base)"
by "whatshell".

- ksh93 - various versions.

You may like to look at: http://www.in-ulm.de/~mascheck/various/whatshell/


I get:

/bin/sh whatshell.sh
SVR4 Bourne shell (SunOS 5 variant)

bosh whatshell.sh
SVR4 Bourne shell (SunOS 5 schily variant)

/bin/ksh whatshell.sh
ksh88 Version (..-)11/16/88i

/usr/xpg4/bin/sh whatshell.sh
ksh88 Version (..-)11/16/88i (posix octal base)

ksh93 whatshell.sh
ksh93 Version M 93t 2008-11-04

or
ksh93 whatshell.sh
ksh93 Version JM 93t+ 2010-03-05

The latter depends on the Solaris version and the first two are added for
completeness...




Jörg
--
EMail:joerg-lSlhzV3CM+2sTnJN9+***@public.gmane.org (home) Jörg Schilling D-13353 Berlin
joerg.schilling-8LS2qeF34IpklNlQbfROjRvVK+***@public.gmane.org (work) Blog: http://schily.blogspot.com/
URL: http://cdrecord.org/private/ http://sourceforge.net/projects/schilytools/files/'
Stephane CHAZELAS
2014-10-23 10:04:06 UTC
Permalink
Post by Joerg Schilling
Post by Stephane Chazelas
AT&T ksh
same as pdksh except that empty positional parameters are
than pdksh I'm undecided about).
Could you be more specific?
What do you understand by "AT&T ksh"?
[...]

I'd say the latest version of ksh93 would represent the "intent"
of AT&T ksh, that is what that shell (and I agree it's probably
a bit too much of a shortcut to say that the latest ksh93
represents AT&T ksh) *means* $@ and $* to be.

If you think there are variations in behaviour in historic
versions or variants that should be brought up here, please feel
free to do so (as you've already done). That is valuable indeed.

The purpose of the discussion, from my point of view is to
decide what the specification should say or not say, so current
and future shell implementations clearly know what they may and
should do.

That's in that context that I try to describe the various
differing behaviours in existence now.

My current view is that POSIX should leave the behaviour
unspecified except for "$@" in list contexts and "$*" so as to
allow consistent behaviours like dash/yash or historic
behaviours like ksh88/ksh93 or consistent behaviours from shells
that support arrays like bash or zsh.
--
Stephane
Joerg Schilling
2014-10-23 08:52:22 UTC
Permalink
Post by Chet Ramey
Post by Stephane Chazelas
be the concatenation of arguments with the first character of
IFS, sometimes with space.
a b
$ bash -c 'set a b; IFS=; a=$*; echo "$a"'
ab
$ bash -c 'set a b; IFS=; a="a bc"; echo ${a#$*}'
c
Yes, the third case is a problem. The other two cases are consistent with
ksh93, mksh, and other Posix shells except dash.
The last two cases differ when you use the POSIX variant of ksh88 and a vanilla
ksh93.

ksh -c 'set a b; IFS=; a=$*; echo "$a"'
a b

ksh93 -c 'set a b; IFS=; a=$*; echo "$a"'
ab

ksh -c 'set a b; IFS=; a="a bc"; echo ${a#$*}'
c

ksh93 -c 'set a b; IFS=; a="a bc"; echo ${a#$*}'
a bc

BTW: in the middle case from the quoted text, the Bourne Shell behaves like the
POSIX variant of ksh88.

Jörg
--
EMail:joerg-lSlhzV3CM+2sTnJN9+***@public.gmane.org (home) Jörg Schilling D-13353 Berlin
joerg.schilling-8LS2qeF34IpklNlQbfROjRvVK+***@public.gmane.org (work) Blog: http://schily.blogspot.com/
URL: http://cdrecord.org/private/ http://sourceforge.net/projects/schilytools/files/'
Joerg Schilling
2014-10-23 09:20:27 UTC
Permalink
Post by Stephane Chazelas
printf '<%s>\n' $*
I cannot see why this should be correct.

Neither the POSIX compliant variant of ksh88 nor
ksh93 ---> version sh (AT&T Research) 93t 2008-11-04
behave this way.

Jörg
--
EMail:joerg-lSlhzV3CM+2sTnJN9+***@public.gmane.org (home) Jörg Schilling D-13353 Berlin
joerg.schilling-8LS2qeF34IpklNlQbfROjRvVK+***@public.gmane.org (work) Blog: http://schily.blogspot.com/
URL: http://cdrecord.org/private/ http://sourceforge.net/projects/schilytools/files/'
Loading...