Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

delcare -a on a nameref in a function modifies nameref instead of target

90 views
Skip to first unread message

Grisha Levit

unread,
Jul 17, 2018, 5:47:38 PM7/17/18
to bug-bash
At global scope this works as expected:

$ declare -n ref=var; declare -a ref=(X); declare -p ref var
declare -n ref="var"
declare -a var=([0]="X")

But in a function, we end up with the nameref variable having both the
`a' and `n' attributes and nothing in the target:

$ f() { declare -n ref=var; declare ref=(X); declare -p ref var; }; f
declare -an ref=([0]="X")
-bash: declare: var: not found

And a slight modification ends up modifying a global variable instead:

$ f() { declare -n ref=var; declare -a ref; ref=(X); declare -p ref
var; }; f; declare -p ref var
declare -an ref=()
-bash: declare: var: not found
declare -a ref=([0]="X")
-bash: declare: var: not found

Greg Wooledge

unread,
Jul 18, 2018, 8:23:41 AM7/18/18
to Grisha Levit, bug-bash
On Tue, Jul 17, 2018 at 05:47:20PM -0400, Grisha Levit wrote:
> At global scope this works as expected:
>
> $ declare -n ref=var; declare -a ref=(X); declare -p ref var
> declare -n ref="var"
> declare -a var=([0]="X")
>
> But in a function, we end up with the nameref variable having both the
> `a' and `n' attributes and nothing in the target:
>
> $ f() { declare -n ref=var; declare ref=(X); declare -p ref var; }; f
> declare -an ref=([0]="X")
> -bash: declare: var: not found

FYI that one is already fixed in 5.0-alpha:

wooledg:~$ declare -n ref=var; declare -a ref=(X); declare -p ref var
declare -n ref="var"
declare -a var=([0]="X")
wooledg:~$ f() { declare -n ref=var; declare ref=(X); declare -p ref var; }; f
declare -an ref=([0]="X")
declare -a var=([0]="X")

Or at least partly fixed. *shrug*

Grisha Levit

unread,
Jul 19, 2018, 1:20:35 PM7/19/18
to woo...@eeg.ccf.org, bug-bash
On Wed, Jul 18, 2018 at 8:23 AM Greg Wooledge <woo...@eeg.ccf.org> wrote:
> FYI that one is already fixed in 5.0-alpha:
>
> wooledg:~$ declare -n ref=var; declare -a ref=(X); declare -p ref var
> declare -n ref="var"
> declare -a var=([0]="X")
> wooledg:~$ f() { declare -n ref=var; declare ref=(X); declare -p ref var; }; f
> declare -an ref=([0]="X")
> declare -a var=([0]="X")
>
> Or at least partly fixed. *shrug*

I think you are just seeing `var' have a value after the function call
because it's still there from the global `declare' invocations.

With bash 5.0 alpha, running just the version that's wrapped in a
function, I don't get any value for `var':

$ echo $BASH_VERSION
5.0.0(1)-alpha
$ f() { declare -n ref=var; declare ref=(X); declare -p ref var; }; f
declare -an ref=([0]="X")
bash: declare: var: not found

Grisha Levit

unread,
Jul 25, 2018, 4:27:49 PM7/25/18
to bug-bash
In the latest devel this issue is fixed for the case that the local nameref
points to a non-existent variable but there is still a bug if the variable
pointed to by a local nameref already exists. In such a case, `declare'
commands after the initial `declare -n' end up modifying the value and/or
attributes of the local nameref variable itself rather than modifying the
target of the nameref.

At global scope:

unset -n ref; unset var
declare var=X; declare -n ref=var; declare ref=(Y); declare -p ref var

declare -n ref="var"
declare -a var=([0]="Y")

Whereas in a function:

unset -n ref; unset var
f() {
declare var=X; declare -n ref=var; declare ref=(Y); declare -p ref var
}; f

declare -an ref=([0]="Y")
declare -- var="X"

Chet Ramey

unread,
Jul 26, 2018, 10:17:36 AM7/26/18
to Grisha Levit, bug-bash, chet....@case.edu
On 7/25/18 4:27 PM, Grisha Levit wrote:
> In the latest devel this issue is fixed for the case that the local nameref
> points to a non-existent variable but there is still a bug if the variable
> pointed to by a local nameref already exists.

Thanks for the report. The original fix was too conservative.


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

Grisha Levit

unread,
Jul 29, 2018, 4:04:43 PM7/29/18
to Chester Ramey, bug-bash
I think there's a related regression in the latest devel commit. Creating a
local variable with the same name as a higher-scoped nameref pointing to an
unset variable creates a local variable with the name of the target of the
nameref.

Starting with:

declare -n ref=var
f() { local ref=Y; declare -p ref var; local; }

This still works fine in both latest and previous:

$ var=X; f
declare -- ref="Y"
declare -- var="X"
ref=Y

But the behavior in the unset target case changed from the expected:

$ unset var; f
declare -- ref="Y"
bash: declare: var: not found
ref=Y

to:

$ unset var; f
declare -n ref="var"
declare -- var="Y"
var=Y

Chet Ramey

unread,
Jul 30, 2018, 11:50:06 AM7/30/18
to Grisha Levit, chet....@case.edu, bug-bash
On 7/29/18 4:04 PM, Grisha Levit wrote:
> I think there's a related regression in the latest devel commit. Creating a
> local variable with the same name as a higher-scoped nameref pointing to an
> unset variable creates a local variable with the name of the target of the
> nameref.

I think forcing the local variable creation to only follow namerefs at
the same variable scope is the right thing to do here.

Chet

Grisha Levit

unread,
Aug 6, 2018, 10:14:16 PM8/6/18
to Chester Ramey, bug-bash
A few more problematic test cases in this vein (tested against latest
devel snapshot 20180803).

f() { local -n ref=var; local -A ref=([1]=); ref=([2]=); declare -p ref var; }

unset ref var; f
# declare -An ref=()
# declare -A var=([1]="" )
declare -p ref
# declare -a ref=([2]="")

unset ref; var=0; f
# declare -An ref=([1]="" )
# declare -- var="0"
declare -p ref
# declare -a ref=([2]="")


f() { local -n ref=var; local -a ref=([1]=); ref=([2]=); declare -p ref var; }

unset ref var; f
# declare -an ref=()
# declare -a var=([1]="")
declare -p ref
# declare -a ref=([2]="")

unset ref; var=0; f
# declare -an ref=([1]="")
# declare -- var="0"
declare -p ref
# declare -a ref=([2]="")


# same issues for `local -[iluctrx] ref=...'
f() { local -n ref=var; local -i ref=([1]=); declare -p ref var; }

unset var; f
# declare -in ref="var"
# declare -ai var=([1]="0")

var=0; f
# declare -in ref="var"
# declare -a var=([1]="")


# same issue for `local -[ilucAa] ref=...'
f() { local -n ref=var; local ref=1; declare -p ref var; }; var=0; f

var=0; f
# bash: local: `1': invalid variable name for name reference
# declare -n ref="var"
# declare -- var="0"

Chet Ramey

unread,
Aug 9, 2018, 10:27:47 AM8/9/18
to Grisha Levit, chet....@case.edu, bug-bash
On 8/6/18 10:13 PM, Grisha Levit wrote:
> A few more problematic test cases in this vein (tested against latest
> devel snapshot 20180803).

Thanks for the report. These are all the same issue, with the same fix.
0 new messages