From: cba...@rajant.com To: bug-bash@gnu.org Subject: indirect variable behavior breakage
Configuration Information [Automatically generated, do not change]: Machine: x86_64 OS: linux-gnu Compiler: gcc Compilation CFLAGS: -DPROGRAM='bash' -DCONF_HOSTTYPE='x86_64' -DCONF_OSTYPE='linux-gnu' -DCONF_MACHTYPE='x86_64-redhat-linux-gnu' -DCONF_VENDOR='redhat' -DLOCALEDIR='/usr/share/locale' -DPACKAGE='bash' -DSHELL -DHAVE_CONFIG_H -I. -I. -I./include -I./lib -D_GNU_SOURCE -DRECYCLES_PIDS -DDEFAULT_PATH_VALUE='/usr/local/bin:/usr/bin' -O2 -g -pipe -Wall -Werror=format-security -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector-strong --param=ssp-buffer-size=4 -grecord-gcc-switches -specs=/usr/lib/rpm/redhat/redhat-hardened-cc1 -m64 -mtune=generic uname output: Linux crucible.rajant.com 4.13.16-100.fc25.x86_64 #1 SMP Mon Nov 27 19:52:46 UTC 2017 x86_64 x86_64 x86_64 GNU/Linux Machine Type: x86_64-redhat-linux-gnu Bash Version: 4.3 (works) Patch Level: 43 # Configuration Information [Automatically generated, do not change]: Machine: x86_64 OS: linux-gnu Compiler: gcc Compilation CFLAGS: -DPROGRAM='bash' -DCONF_HOSTTYPE='x86_64' -DCONF_OSTYPE='linux-gnu' -DCONF_MACHTYPE='x86_64-redhat-linux-gnu' -DCONF_VENDOR='redhat' -DLOCALEDIR='/usr/share/locale' -DPACKAGE='bash' -DSHELL -DHAVE_CONFIG_H -I. -I. -I./include -I./lib -D_GNU_SOURCE -DRECYCLES_PIDS -DDEFAULT_PATH_VALUE='/usr/local/bin:/usr/bin' -O2 -g -pipe -Wall -Werror=format-security -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector-strong --param=ssp-buffer-size=4 -grecord-gcc-switches -specs=/usr/lib/rpm/redhat/redhat-hardened-cc1 -m64 -mtune=generic -Wno-parentheses -Wno-format-security uname output: Linux 807847456c29 4.15.3-300.fc27.x86_64 #1 SMP Tue Feb 13 17:02:01 UTC 2018 x86_64 x86_64 x86_64 GNU/Linux Machine Type: x86_64-redhat-linux-gnu Bash Version: 4.4 (does not work) Patch Level: 12 Release Status: release Description: a simple function that is used to test if a var is indirect or not and return the value whether indirect or simply a string is no longer working as expected on newer versions of bash. Repeat-By: This function works fine on this version (4.3.43) of bash (and all previous versions I have access to, e.g. 4.2.46). It is broken, that I am aware of, in 4.4.12 and 4.4.19, and possibly other versions as well. function ivar() { echo -n "${!1:-${1}}"; } This will take in a word as $1, and if it is a ref, will echo the value of ref, but if it is not, will simply echo $1. This function cares not about the string handed in, it rejects the indirection silently, and IMHO correctly, regardless of the characters in that string. I have found this function to be incredibly handy, and it's in extensive use. It's simplicity and usefulness are very much relied upon. Now, if the string starts with a number, or has a dash (possibly other chars as well), it throws a syntax error. It's not clear to me why it now feels the need to do this. Usage: # in a working bash version: $ ping=pong $ ivar "${ping}" pong <-result $ ivar 1.0.0 1.0.0 <-result $ ivar m-4 m-4 <-result $ declare -A myhash=( [foo]=bar [bar]=baz [baz]=foo ) $ ivar "myhash[@]" baz foo bar <-result $ ivar "myhash[foo]" bar <-result # in a newer, non-working bash version: $ ivar 1.0.0 bash: 1.0.0: bad substitution <-result $ ivar m-4 bash: m-4: bad substitution <-result Fix: The fix is to please restore the previous behavior. I'm assuming it's that no one noticed this use-case breakage, or they would not have made the change. I think what's happened is before, bash looked into it's environment to see if the string matched an already defined variable, and if it did, it returned the value of the match. I think a change was introduced that says, hey I'm going to see if this is a validly formatted variable name first, and if not throw an error. The prior way also did that, but it did it when the actual variable was set, not when it was being looked up. Obviously, it won't find a match if the name is invalid, so this may have been seen as an optimization. But in this case, it would simply be better to return nothing and do nothing, not throw an error. The name does not NEED to be valid here. Anyway, that my guess :) Thanks for looking into it, Regards, Christopher Barry Rajant