#598239 dash local assignment splits words

Package:
dash
Source:
dash
Description:
POSIX-compliant shell
Submitter:
Stephen Gildea
Date:
2011-09-27 01:18:14 UTC
Severity:
wishlist
#598239#5
Date:
2010-09-27 17:52:02 UTC
From:
To:
Using the "local" command to do variable assignment should not do word
splitting.  The following script shows how a Dash function incorrectly
handles an argument with a space in it.


#! /bin/dash

show_buggy_word_splitting() {
    local d=$1
    if [ "$d" = "two words" ]; then
        echo Success
        return 0
    else
        echo Failure
        return 1
    fi
}

show_buggy_word_splitting "two words"

#598239#8
Date:
2010-09-27 18:59:41 UTC
From:
To:
Dash is actually working as expected: 'local' is a built-in and as any other
built-in or command, when you don't quote a variable it is expanded:

count() {
    echo got $#
}
show_buggy_word_splitting() {
    local d=$1
    # think of:
    count d="$1"
    count d=$1
    if [ "$d" = "two words" ]; then
        echo Success
        return 0
    else
        echo Failure
        return 1
    fi
}

show_buggy_word_splitting "two words"

Bash and others treat 'local' (just like export, etc) differently, but it's a
known shell portability issue.

Another example:
special_expansion() {
    echo Quoted:
    export ex="$1"
    env | grep words
    echo Unquoted:
    export ex=$1
    env | grep words
}

special_expansion "two words=foo"

$ dash /tmp/t.sh
Quoted:
ex=two words=foo
Unquoted:
words=foo
$ bash /tmp/t.sh
Quoted:
ex=two words=foo
Unquoted:
ex=two words=foo

Cheers,

#598239#13
Date:
2010-09-29 18:39:42 UTC
From:
To:
Wait, so you're telling me that

VAR=$stuff
export VAR

and

export VAR=$stuff

parse differently from each other in Dash, and this is not considered
a bug?  If so, I have to say that it appears Bash got it right here.

#598239#18
Date:
2010-09-29 19:19:31 UTC
From:
To:
Stephen Gildea wrote:

Yes.  It is even required behavior, if I understand correctly.  See
http://unix.org/2008edition [1] (search for "sh -").

A "simple command" is a sequence of assignments and redirections,
optionally followed by words and redirections, terminated by a
control operator (see section 2.9.1).  It is parsed like this:

 1. First, variable assignments and redirections are collected.
    Only assignments _preceding_ the command name count here.

 2. Next, all _other_ words are expanded and split into fields.

 3. Redirections are performed.

 4. Variable assignments are expanded and evaluated.

So if I understand correctly, any shell that does _not_ make

	v="a b"
	export foo=$v

have the same meaning as

	foo=a
	export foo
	export b

is non-compliant.

Perhaps you might find it worth clarifying the standard to loosen this
requirement so bash does not get changed to follow dash's behavior?
See http://www.austingroupbugs.net/ if you would like to do so.

[1] http://www.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html

#598239#23
Date:
2010-10-03 12:10:53 UTC
From:
To:
Stephen Gildea wrote:
removed.

See Changelog.O in the dash source tree:
On Sun, 23 Nov 1997 12:45:15 +1100, ash 0.3.1-14:
  * Disabled word-splitting for assignment builtins.
On Mon, 24 Nov 1997 16:19:10 +1100:
  * Fixed incorrect assignment builtin code.
On Sun, 15 Jul 2001 17:27:03 +1000, ash 0.3.8-15:
  * Removed assignment builtins since it is at best undefined by the SuS and
    also can't be implemented consistently.

Unfortunately, neither the dash git repository nor the dash mailing list
archives I can find go back that old.

When the "treat words that look like assignments specially" behaviour
triggers exactly differs between shells that implement it.

In ksh93 it is fairly consistent: all builtins it applies to are
special, so that when a word looks like such a builtin it is one. (ksh93
doesn't have "local", its "alias" is special, different from what POSIX
requires, and its extension "typeset" is also special.) The command word
may contain quoting but no expansions to be a candidate for this special
treatment.

In bash and mksh, it applies to various non-special builtins that can at
least be overridden with a function. The special behaviour does not
depend on whether the actual builtin is going to be called, or a
user-defined function. The command word must be the literal builtin, no
quoting or expansions are permitted.

Some versions of bash and zsh, configured with certain options, apply
the special casing to all words that look like assignments.

Another effect of the special casing is that tilde expansion is
performed in cases like
  export PATH=foo:~/bin:bar

I agree with the other post that POSIX does not require this behaviour,
and might even prohibit it; the prohibition is probably not intended,
though, and it seems unlikely to me the standard will be changed to
prohibit it -- that would break more than it fixes.