[Top][All Lists]

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: Word splitting for $@ in variable assignment

From: Greg Wooledge
Subject: Re: Word splitting for $@ in variable assignment
Date: Thu, 24 Jun 2021 07:32:15 -0400

On Thu, Jun 24, 2021 at 05:52:47PM +1000, Alvin Seville wrote:
>  Hello! I want to understand why the following code doesn't produce any
> error:
> set -- "a b" "c"
> a="$@"

It doesn't produce an error because the designers of the shell tried
to make it "user-friendly" by having it guess what you really want,
whenever you do silly things.  Sometimes it guesses correctly.  Sometimes

In this case, you've written code that makes no sense to an experienced
programmer, because on the surface you're assigning a vector (list, array)
value to a scalar (string) variable.

But the shell decided it would try to "help" you by assuming you really
meant a="$*".  Except, it's not actually that simple, and it just gets
more and more ugly the deeper you dive into it.

> ? I expected smth like: main.sh: line 2: b: command not found due to word
> splitting according to documentation
> <https://www.gnu.org/savannah-checkouts/gnu/bash/manual/bash.html#Shell-Parameters>.
> What am I missing?

Word splitting does not occur on the right hand side of a string variable
assignment.  That's why you can do this:

a='two words'

This is well-defined behavior, completely portable across every Bourne-type
shell ever written.

The difference between this and your case (a="$@") is that "$@" doesn't
actually involve word splitting.  It's like... the opposite of word
splitting.  Word retention, maybe?  It doesn't have a name.

But it doesn't make sense for a retained list of words to be assigned to
a string variable.  There has to be a single string that gets assigned.
So the shell tries to come up with a result that it thinks will make

What it ends up doing is taking the list of words generated by "$@" and
concatenating them all into a single string with spaces between them.
It does NOT use the contents of IFS -- it simply chooses "space" as
the separator.

unicorn:~$ bash
unicorn:~$ IFS=x
unicorn:~$ set -- "a b" c
unicorn:~$ a="$*"; echo "$a"
a bxc
unicorn:~$ a="$@"; echo "$a"
a b c

This surprising leniency is one of the reasons there are so many terrible
shell scripts (and shell script writers) in the world.  The shell lets you
do many ridiculous and even dangerous things, with no warnings of any kind.

reply via email to

[Prev in Thread] Current Thread [Next in Thread]