Path: csiph.com!au2pb.net!usenet.blueworldhosting.com!feeder01.blueworldhosting.com!news.glorb.com!usenet.stanford.edu!not-for-mail From: Linda Walsh Newsgroups: gnu.bash.bug Subject: Dynamic variable failure & equiv-const strings compare unequal Date: Thu, 22 Oct 2015 03:01:06 -0700 Lines: 175 Approved: bug-bash@gnu.org Message-ID: NNTP-Posting-Host: lists.gnu.org Mime-Version: 1.0 Content-Type: text/plain; charset=UTF-8; format=flowed Content-Transfer-Encoding: 7bit X-Trace: usenet.stanford.edu 1445508079 18540 208.118.235.17 (22 Oct 2015 10:01:19 GMT) X-Complaints-To: action@cs.stanford.edu To: bug-bash Envelope-to: bug-bash@gnu.org User-Agent: Thunderbird X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x (no timestamps) [generic] X-Received-From: 173.164.175.65 X-BeenThere: bug-bash@gnu.org X-Mailman-Version: 2.1.14 Precedence: list List-Id: Bug reports for the GNU Bourne Again SHell List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Xref: csiph.com gnu.bash.bug:11739 Greg Wooledge wrote: > Also I think you are completely misrepresenting the dynamic variable > scope system that bash uses. Variables are not just global or local. > There's an entire stack of them. When you reference a > variable (let's say i) inside a function, bash searches up > through the call stack looking for a variable named > i until it finds one. ---- So where in the manpage is the behavior documented -- I'd like to reread it to ensure I don't have any misconceptions. The reason being is that out of 4 tests below, 2 fail. It appears test 2 failing is a failure of the dynamic scoping system. Test 3 was meant to be an extension, as I have some code where I change a member in a hash, and try to compare the final result with a known correct value, but as in test-2 all the other members of the hash disappear Notice that 'parts' is defined at the global level as an array. in tst0 & tst1, I locally change the value of IFS, and call "assignparts" that splits the value "$ip" based on the "localized" values of IFS -- tst0 + tst1 work as I'd expect with dynamic scoping. Since parts was declared 'global', the different splitting caused by differing 'IFS' values is reflected in the global. However, in tst3, I only change 1 member in the parts array, via "parts[1]=222". before the assignment, parts=(1 .2 .3 .4) but after the assignment "parts[1]=222", the entire array was wiped. I.e. test output was: Case 2 got/Expected: "222" "1\ 222\ .3\ .4" instead of it only replacing the 2nd member of parts, the entire array was wiped. The same happens if parts is a 'hash' -- trying to only replace 1 member of the hash results in the entire hash being wiped. I don't see how this is correct function for "dynamically scoped" variables -- which is why I need to reread (or read) the manpage descriptions of how dynamic vars are *supposed* to work, as they don't seem to be working by "unwinding" the call stack and using the last definition of 'parts' (which is at the global level). test 3 --- was supposed to check the values of the hash field-by-field, but first I thought to check them when printed out in a specific order as 2 identical strings. The strings look identical, yet don't compare equal. so it seemed pointless to try to break down test 3's output into a field-by-field comparison when I couldn't even get the identical strings that contained the fields to compare. tests 2 & 3 work backward from a program where I try to change 1 value in a hash (vs. the array in test2), but end up with the local assignments of values->[keys] not being propagated, at all, to the global frame where the has is declared. I.e. these examples of dynamic variable declarations and usage don't seem to work as I understand the concept, but there is nothing about bash's 'dynamic variables' in the manpage. -l ----- #!/bin/bash shopt -s expand_aliases ; alias my=declare alias array='my -a' int='my -i' ip=10.20.30.40 array parts=() array answers=( '10 20 30 40' '1 .2 .3 .4' '1 222 .3 .4' '192.168.0.1/24::{ [ipaddr]="192.168.0.1/24" [address]="192.168.0.1" [prefixlen]="24" ; }' ) array addr_fields=(ipaddr address prefixlen) assignparts() { parts=( $ip ) ; } tst0 () { my IFS=. ; assignparts ; echo -E "${parts[@]}"; } tst1 () { my IFS=0 ; assignparts ; echo -E "${parts[@]}"; } tst2 () { parts[1]=222; echo -E "${parts[@]}" ; } tst3 () { my ipaddr="$1"; shift; int status=0 my pat='^([^/]+)/([0-9]+)\s*$' my address prefixlen if [[ ! $ipaddr =~ $pat ]]; then echo >&2 "Error in ip/netsize format: \"$ipaddr\"" status=1 else address=${BASH_REMATCH[1]} prefixlen=${BASH_REMATCH[2]} my out="" for flds in "${addr_fields[@]}"; do out+="[$flds]=\"${!flds}\" " done printf "{ %s; }" "$out" fi return $status } int passno=0 tests=0 my fmt="Case %d got/Expected:\n \"%q\"\n \"%q\"\n" testor () { int tstno my out="" for tstno in {0..3}; do tests+=1 exp="${answers[tstno]}" if [[ $exp =~ :: ]]; then my args="${exp%::*}" exp="${exp#*::}" out="$(tst$tstno $args)" else out="$(tst$tstno)" fi if [[ $out != $exp ]]; then printf >&2 "$fmt" "$tstno" "$out" "$exp" continue fi passno+=1 done } testor echo "Passed $passno/$tests tests." ---------------- output: Case 2 got/Expected: "222" "1\ 222\ .3\ .4" Case 3 got/Expected: "\{\ \[ipaddr\]=\"192.168.0.1/24\"\ \[address\]=\"192.168.0.1\"\ \[prefixlen\]=\"24\"\ \;\ \}" "\{\ \[ipaddr\]=\"192.168.0.1/24\"\ \[address\]=\"192.168.0.1\"\ \[prefixlen\]=\"24\"\ \;\ \}" Passed 2/4 tests. The outputs for case 3 look identical -- I was using %s to print them out, but switched to "%q", to ensure no hidden chars... case 2 -- ??? Why didn't it only change the 1 member?