Configuration Information [Automatically generated, do not change]:
Machine: x86_64
OS: linux-gnu
Compiler: gcc
Compilation CFLAGS: -march=x86-64 -mtune=generic -O2 -pipe -fno-plt
-fexceptions -Wp,-D_FORTIFY_SOURCE=3 -Wformat -Werror=format-security
-fstack-clash-protection -fcf-protection -fno-omit-frame-pointer
-mno-omit-leaf-frame-pointer -g
-ffile-prefix-map=/build/bash/src=/usr/src/debug/bash -flto=auto
-DDEFAULT_PATH_VALUE='/usr/local/sbin:/usr/local/bin:/usr/bin'
-DSTANDARD_UTILS_PATH='/usr/bin' -DSYS_BASHRC='/etc/bash.bashrc'
-DSYS_BASH_LOGOUT='/etc/bash.bash_logout' -DNON_INTERACTIVE_LOGIN_SHELLS
-std=gnu17
uname output: Linux desktop 6.18.29-1-lts #1 SMP PREEMPT_DYNAMIC Mon, 11 May
2026 07:46:10 +0000 x86_64 GNU/Linux
Machine Type: x86_64-pc-linux-gnu
Bash Version: 5.3
Patch Level: 9
Release Status: release
Description:
When an array is declare'd within a function with some variation of "-ga" or
"-A" in quotes, the variable is created with inconsistent properties and may
have incorrect values. That is,
f() { declare -ga arr=(1 2 3); }
works as expected, but with
f() { declare "-ga" arr=(1 2 3); }
1) 'local -p arr' succeeds inside f() and the value is lost on return;
2) 'declare -p arr' outside f() shows a variable with no value, not even '=()';
3) the variable can not be found with "${!arr@}";
It gets even worse with associative arrays.
$ f() { declare "-gA" arr=([a]=1 [b]=2); declare -p arr; }; f; declare -p arr
declare -a arr=([0]="2")
declare -A arr
$ f() { local "-A" loc=([a]=1 [b]=2); local -p loc; }; f
bash: local: arr: cannot convert indexed to associative array
declare -a arr=([0]="2")
Both cases work properly when quotes are removed.
Non-arrays are not affected, eg. "-gi" works as expected in spite of the quotes.
This was discovered in an eval context, hence the paranoid overquoting.
Repeat-By:
#!/bin/bash
#set -u
f() {
declare "-g" -- qg="text"
declare -g -- ug="text"
declare "-gi" -- qgi="123"
declare -gi -- ugi="123"
declare "-ga" -- qga=("elem1" "elem2")
declare -ga -- uga=("elem1" "elem2")
declare "-ga" -- qga2=([0]="elem1" [1]="elem2")
declare -ga -- uga2=([0]="elem1" [1]="elem2")
declare "-gia" -- qgia=("3" "2" "1" "zero")
declare -gia -- ugia=("3" "2" "1" "zero")
declare "-gA" -- qgA=([a]="elem1" [b]="elem2")
declare -gA -- ugA=([a]="elem1" [b]="elem2")
declare "-giA" -- qgiA=([a]="3" [b]="2" [c]="1" [d]="zero")
declare -giA -- ugiA=([a]="3" [b]="2" [c]="1" [d]="zero")
printf '\nlocals (should be none; "local: name: not found" suppressed):\n'
local -p qg ug qgi ugi qga uga qga2 uga2 qgia ugia qgA ugA qgiA ugiA \
2>/dev/null
}
f
printf '\nglobals (declared with opts quoted then unquoted):\n'
declare -p qg ug qgi ugi qga uga qga2 uga2 qgia ugia qgA ugA qgiA ugiA
Besides the surprising output from that script, when run with 'set -u' it also
reveals this:
./bug.sh: line 13: zero: unbound variable
So bash is also somehow trying to use an array value as a variable name.