Stephane Chazelas
2014-10-20 21:54:20 UTC
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
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).
"Field Splitting" is not performed within double quotes. The
link doesn't clearly state *where* field splitting is performed.
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).
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 shListed 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.
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 thatand where field splitting (see Field Splitting) is
performed,
"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 ina 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.
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
Stephane