local var="$@" doesn't behave like every other system
Affects | Status | Importance | Assigned to | Milestone | |
---|---|---|---|---|---|
dash (Ubuntu) |
New
|
Undecided
|
Unassigned |
Bug Description
With Ubuntu (for many years), the following code in /bin/sh (i.e. dash):
f()
{
local v="$@"
echo "<$v>"
}
f "$@"
behaves differently to /bin/sh on Debian, macOS, FreeBSD, Solaris (/usr/xpg4/bin/sh).
The behaviour of "$@" is very special. When there are no arguments, it completely
disappears (i.e. even the surrounding quotes disappear so that there are no words). When
there are arguments, it replicates those arguments perfectly (i.e. it effectively produces
multiple quoted arguments if necessary).
The described behaviour applies when "$@" is used for local variable assignment on Ubuntu,
which sounds consistent with other uses of "$@" and therefore correct, but it doesn't
match the behaviour on any other system, and is therefore a problem for shell portability.
On the other systems mentioned above, the behaviour of "$@" when used as the value of a
variable assignment (local or not) is as though "$*" had been used (i.e. it produces a
single argument containing all the words).
The difference is clear when the arguments contain multiple words. On Ubuntu, only
the first word is assigned to v. Any subsequent words are treated as subsequent variable
names. This goes unnoticed if the subsequent words are valid variable identifiers.
But if the subsequent words are not valid identifiers, then dash emits a "bad variable name"
error message.
Note that without the "local" keyword, "$@" does behave like "$*" (like all the other systems).
You might think that this is correct behaviour, but it is contrary to non-local variable
assignment, and contrary to all other systems, and is therefore unhelpful. Please change
it to behave like dash on other systems, e.g. debian.
This behaviour has been witnessed on ubuntu-16.x and ubuntu-20.04.
I thought I'd illustrate the problem. Given a #!/bin/sh script like this called tst:
#!/bin/sh
f()
{
local v="$@"
echo "<$V>"
}
f "$@"
On Debian, Fedora, FreeBSD, OpenBSD, macOS, and Solaris, the arguably incorrect
but more useful behaviour is:
> ./tst a b c
<a b c>
> ./tst 1 2 3
<1 2 3>
On Ubuntu, the arguably correct but less useful behaviour is:
> ./tst a b c
<a>
> ./tst 1 2 3
./tst: 4: local: 2: bad variable name
On NetBSD, the behaviour is very similar to Ubuntu's, but not identical:
> ./tst a b c
<a>
> ./tst 1 2 3
local: 2: bad variable name
<1>
It seems that "bad variable name" is a fatal error on Ubuntu, but not on NetBSD.