Re: [BUG] 'unset' fails silently under specific conditions

2018-05-02 Thread Martijn Dekker

Op 02-05-18 om 02:20 schreef Chet Ramey:

You complained that `typeset +x' didn't `unexport' a variable.  The reason > is 
that the variable assignment preceding the special builtin caused a
variable to be created at the global scope, and the `typeset' resulted in
a local variable being created.


I still can't see how that is relevant here: 'typeset'/'declare' is not 
involved in the current issue. But then, neither is 'unset'. It does 
appear that the current issue is not what I thought it was.


Instead, in POSIX mode, it looks like a variable assignment preceding a 
special builtin may create a variable at a function-local scope without 
'typeset'/'declare' being involved at all. But not always.


Let's see if I'm getting it right this time. In the following:
set -o posix
f() { foo=bar : ; }
f
the command 'foo=bar :'
1. makes the assignment 'foo=bar' survive the ':' command;
2. gives 'foo' a global scope;
3. permanently exports the global variable 'foo'.

However, in the following:
set -o posix
f() { foo=bar; foo=baz : ; }
f
the plain assignment 'foo=bar' creates an ordinary global variable named 
'foo' with value 'bar', and then the command 'foo=bar :'
1. makes the assignment 'foo=baz' survive the ':' command, but by 
creating *another* 'foo' instead of overwriting the first;

2. gives that other 'foo' a function-local scope;
3. exports the local variable 'foo' for the duration of its existence.

My testing confirms that this is what appears to happen, and I think 
it's a bug, because (1) POSIX has no notion of variables with a 
function-local scope; (2) even if it did, no command was issued that 
should make the variable local to the function; and (3) the behaviour in 
the second example is inconsistent with that in the first.


I think 'foo=baz :' should act the same in the second example as 
'foo=bar :' does in the first, i.e.: if there is already a variable by 
that name it should be overwritten, just like with any normal shell 
assignment.


- M.



Re: [BUG] 'unset' fails silently under specific conditions

2018-05-02 Thread Greg Wooledge
On Wed, May 02, 2018 at 03:07:42PM +0100, Martijn Dekker wrote:
> Let's see if I'm getting it right this time. In the following:
>   set -o posix
>   f() { foo=bar : ; }
>   f
> the command 'foo=bar :'
> 1. makes the assignment 'foo=bar' survive the ':' command;
> 2. gives 'foo' a global scope;
> 3. permanently exports the global variable 'foo'.

Here's what I get:

wooledg:~$ bash
wooledg:~$ set -o posix
wooledg:~$ f() { foo=bar : ; }; f
wooledg:~$ declare -p foo
declare -x foo="bar"
wooledg:~$ declare +x foo
wooledg:~$ declare -p foo
declare -- foo="bar"

So, 1 and 2 are correct, but it's not "permanently" exported.  The
export flag is removable.

> However, in the following:
>   set -o posix
>   f() { foo=bar; foo=baz : ; }
>   f
> the plain assignment 'foo=bar' creates an ordinary global variable named
> 'foo' with value 'bar', and then the command 'foo=bar :'
> 1. makes the assignment 'foo=baz' survive the ':' command, but by creating
> *another* 'foo' instead of overwriting the first;
> 2. gives that other 'foo' a function-local scope;
> 3. exports the local variable 'foo' for the duration of its existence.

That isn't what I see.

wooledg:~$ bash
wooledg:~$ set -o posix
wooledg:~$ f() { foo=bar; foo=baz : ; }; f
wooledg:~$ declare -p foo
declare -x foo="baz"

What did you see that led you to conclude there is a local variable
involved?  (Not counting discussions with Chet!)

wooledg:~$ bash
wooledg:~$ set -o posix
wooledg:~$ f() { foo=bar; declare -p foo; foo=baz :; declare -p foo; }; f
declare -- foo="bar"
declare -x foo="baz"
wooledg:~$ declare -p foo
declare -x foo="baz"

All the evidence I'm seeing points to just plain global variables in
this example.

wooledg:~$ bash
wooledg:~$ set -o posix
wooledg:~$ f() { foo=bar :; declare +x foo; declare -p foo; }; f
declare -- foo="bar"
wooledg:~$ declare -p foo
declare -x foo="bar"

Same here.  Global variable, survives the function, no longer exported.



Re: [BUG] 'unset' fails silently under specific conditions

2018-05-02 Thread Greg Wooledge
On Wed, May 02, 2018 at 10:32:52AM -0400, Greg Wooledge wrote:
> wooledg:~$ bash
> wooledg:~$ set -o posix
> wooledg:~$ f() { foo=bar; foo=baz : ; }; f
> wooledg:~$ declare -p foo
> declare -x foo="baz"
> 
> What did you see that led you to conclude there is a local variable
> involved?  (Not counting discussions with Chet!)

After sending that, I saw the Subject: header, and figured maybe you
left something out in your example.  Trying again, this time with an
unset command in the mix:

wooledg:~$ bash
wooledg:~$ set -o posix
wooledg:~$ f() { foo=bar; declare -p foo; foo=baz :; declare -p foo; unset foo; 
declare -p foo; }; f
declare -- foo="bar"
declare -x foo="baz"
declare -- foo="bar"
wooledg:~$ declare -p foo
declare -- foo="bar"
wooledg:~$ env | grep foo=
wooledg:~$ 

*NOW* there's evidence of a local variable, because unset removes it
and exposes the global.  But it's not "permanently exported" as far as
I can see.



Re: [BUG] 'unset' fails silently under specific conditions

2018-05-02 Thread Martijn Dekker

Op 02-05-18 om 15:38 schreef Greg Wooledge:

*NOW* there's evidence of a local variable, because unset removes it
and exposes the global.


Right. That's what triggered my initial report, in which I confused that 
phenomenon for a failure of the 'unset' command to unset the variable.



  But it's not "permanently exported" as far as  I can see.


Sorry for the inexact use of language -- I simply meant that the global 
scope of the variable acquired the export flag, as opposed to the 
function-local scope.


- M.



Re: [BUG] 'unset' fails silently under specific conditions

2018-05-02 Thread Chet Ramey
On 5/2/18 10:07 AM, Martijn Dekker wrote:
> Op 02-05-18 om 02:20 schreef Chet Ramey:
>> You complained that `typeset +x' didn't `unexport' a variable.  The
>> reason > is that the variable assignment preceding the special builtin
>> caused a
>> variable to be created at the global scope, and the `typeset' resulted in
>> a local variable being created.
> 
> I still can't see how that is relevant here: 'typeset'/'declare' is not
> involved in the current issue. But then, neither is 'unset'. It does appear
> that the current issue is not what I thought it was.
> 
> Instead, in POSIX mode, it looks like a variable assignment preceding a
> special builtin may create a variable at a function-local scope without
> 'typeset'/'declare' being involved at all. But not always.

Mostly correct. It creates a variable that claims to be at the global scope
(context == 0, internally), but is placed in the wrong variable table. This
is the bug. It manifests itself in different ways.

What we're trying to figure out is the right semantics: should it continue
to create the variable at the global scope (context == 0) and make sure it
is inserted into the correct variable table (global_variables), or should
it create a variable at the current scope (context ==
current_variable_context) and insert it into the variable table at the
current scope (shell_variables).

> 
> Let's see if I'm getting it right this time. In the following:
> set -o posix
> f() { foo=bar : ; }
> f
> the command 'foo=bar :'
> 1. makes the assignment 'foo=bar' survive the ':' command;
> 2. gives 'foo' a global scope;
> 3. permanently exports the global variable 'foo'.
> 
> However, in the following:
> set -o posix
> f() { foo=bar; foo=baz : ; }
> f
> the plain assignment 'foo=bar' creates an ordinary global variable named
> 'foo' with value 'bar', and then the command 'foo=bar :'
> 1. makes the assignment 'foo=baz' survive the ':' command, but by creating
> *another* 'foo' instead of overwriting the first;
> 2. gives that other 'foo' a function-local scope;
> 3. exports the local variable 'foo' for the duration of its existence.

Pretty much.

> My testing confirms that this is what appears to happen, and I think it's a
> bug, because (1) POSIX has no notion of variables with a function-local
> scope; (2) even if it did, no command was issued that should make the
> variable local to the function; and (3) the behaviour in the second example
> is inconsistent with that in the first.
> 
> I think 'foo=baz :' should act the same in the second example as 'foo=bar
> :' does in the first, i.e.: if there is already a variable by that name it
> should be overwritten, just like with any normal shell assignment.

If there is an existing global variable by that name, you mean. If there is
an existing local variable, the assignment preceding the special builtin
will completely bypass it and modify the global scope. (Just to make things
a little more interesting, if you use ksh-style functions to test local
variables -- since Posix-style functions don't have local variables --
ksh93 modifies an existing local variable instance.)

My original fix was the second alternative described above, which is
similar to the ksh93 local variable behavior: create or modify a local
variable instance if executing within a shell function.

After our subsequent discussion, and this second report, I modified it to
implement the first alternative: create and modify global variables and
leave existing local variables unaltered.  We'll see how that goes.

-- 
``The lyf so short, the craft so long to lerne.'' - Chaucer
 ``Ars longa, vita brevis'' - Hippocrates
Chet Ramey, UTech, CWRUc...@case.eduhttp://tiswww.cwru.edu/~chet/



Minor 'help' defect.

2018-05-02 Thread thutt

I'd like to report the minor issue that the 'help builtin' command has
an extra '.' at the end of the 'exit status' section.

  bash --version
  GNU bash, version 4.2.25(1)-release (x86_64-pc-linux-gnu)

  builtin: builtin [shell-builtin [arg ...]]
  Execute shell builtins.

  Execute SHELL-BUILTIN with arguments ARGs without performing command
  lookup.  This is useful when you wish to reimplement a shell builtin
  as a shell function, but need to execute the builtin within the function.

  Exit Status:
  Returns the exit status of SHELL-BUILTIN, or false if SHELL-BUILTIN is
  not a shell builtin..

--
Selenium is a failed Intel experimental CPU made from Brazil Nuts.