Subject: Re: [bug-diffutils] bug#24116: [platform-testers] new snapshot available: diffutils-3.3.50-0353

From: Eric Blake <[email-masked]>
Date: Mon, 1 Aug 2016 09:27:58 -0600

On 07/31/2016 06:36 PM, Jim Meyering wrote:

> dash's printf builtin handles \e differently -- that's easy to work
> around: use \033, which *is* portable.
> More surprising is that this generates no output:
> 
>   dash -c 'f() { local t=$(printf '\''\t\t'\''); printf "$t"; }; f'

That's because you made the classic mistake of using local AND assigning
to the variable at the same time.

This works:

dash -c 'f() { local t; t=$(...); printf "$t"; }; f'

The difference? There is a notion of an assignment context:
http://austingroupbugs.net/view.php?id=351

Bash treats 'local' like 'export' in introducing an assignment context
(so "" around local t=$() is optional); but 'local' is not specified by
POSIX, so dash does NOT treat it as an assignment context.  Since local
is a command name, you MUST use "" in all subsequent words, or else
defer the actual assignments to standalone statements, to get assignment
context.

> 
> I.e., piping it into wc -c prints 0.
> With bash, it prints the expected pair of TAB bytes.
> I found that I could work around this nonsensical behavior by hoisting
> the "tab=..." definition up/out of those two functions, or by adding
> standard-says-never-necessary double quotes like this:
> 
>   dash -c 'f() { local t="$(printf '\''\t\t'\'')"; printf "$t"; }; f'

Umm, the standard is silent.  local is not defined by the standard.

> 
> However, I prefer not to work around it here (and in every other test
> script where this comes up), and will insulate all of our test scripts
> by rejecting any shell with that misbehavior, so plan to adjust
> init.sh to select another shell when it finds this flaw.

It's not a flaw in dash, but in your expectations.

-- 
Eric Blake   eblake redhat com    +1-919-301-3266
Libvirt virtualization library http://libvirt.org