Re: Dynamic variable failure & equiv-const strings compare unequal
On Thu, Oct 22, 2015 at 03:01:06AM -0700, Linda Walsh wrote: > [cut] > I.e. test output was: > Case 2 got/Expected: > "222" > "1\ 222\ .3\ .4" > [cut] You didn't initialize the array. By the time you do "parts[1]=222" it's still empty. And in your previous message you tried to initialize it in a subshell. Variables don't retain their values after returning from subshells. > [cut] > 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. > [cut] > [cut] >if [[ $out != $exp ]]; then > [cut] Bash uses unquoted characters on the right side of == and != as wildcard patterns. For example, [ipaddr] in $exp means "any of i, p, a, d, r". You should quote the right operand. > #!/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? > > > > > > >
Re: Dynamic variable failure & equiv-const strings compare unequal
On Thu, Oct 22, 2015 at 05:13:45AM -0700, Linda Walsh wrote: > Oleg Popov wrote: > > On Thu, Oct 22, 2015 at 03:01:06AM -0700, Linda Walsh wrote: > >> [cut] > >> I.e. test output was: > >> Case 2 got/Expected: > >> "222" > >> "1\ 222\ .3\ .4" > >> [cut] > > > > You didn't initialize the array. By the time you do "parts[1]=222" it's > > still empty. And in your previous message you tried to initialize it in > > a subshell. Variables don't retain their values after returning from > > subshells. > > I was testing if dynamic scoping included subshells, I > didn't think so, but that doesn't mean I don't test it. I removed > it though, as it confused the example. > > ip and 'parts' are both initialized in global. > > testor calls (tst0, tst1, tst2 & tst3). > > tst0 & tst1 both call "assignparts" which uses the global > value of $ip to set the global value of parts. I.e. since > neither "ip" nor 'parts' are declared inside of any of the > functions, they should use the top-level global values, no? > > tst2, using the last global value set in tst1, only tries to > change 1 value in 'parts'... i.e. why would 'ip' reference the > global value of 'ip', but not parts? > > ip and parts are declared at the same scope (global), so why > wouldn't the global 'parts' be initialized as well? $(...) is a subshell. Variables cannot be passed back from a subshell, no matter how and where they are declared. > > Bash uses unquoted characters on the right side of == and != as > > wildcard patterns. For example, [ipaddr] in $exp means "any of i, p, > > a, d, r". You should quote the right operand. > --- > Ahh... or if I quote both sides > using 'printf "%q"' first, that should do the same, no? No. Just use double quotes: [[ $var1 == "$var2" ]] > So, ok, I get that one -- but the first looks sketchy, > as ip and parts are both, only defined at the global level, > thus my expectation that just like it used the global value of > 'ip' for tst0 & tsts1 -- it should have stored the split version > of it in the global value of parts... I really don't get why > it would use the global value as a dynamic in 1 case but not > the other...?
Re: Design question(s), re: why use of tmp-files or named-pipes(/dev/fd/N) instead of plain pipes?
On Sat, Oct 17, 2015 at 05:43:15PM -0700, Linda Walsh wrote: > [cut] > from a semantic point of view, how is: > >readarray foo < <(cat /etc/passwd) > > different from > >shopt -s lastpipe >cat /etc/passwd |readarray foo > > Is there something in the semantics that would require they > be implemented differently? > [cut] readarray < <(...) is not something "implemented" since it's not a single feature. It's a combination of two unrelated features ("<" and "<(...)") and unlikely an intended way to use <(...). <(...) and >(...) let you insert stream producers and consumers (which are processes) into a command as filenames. Example: diff <(curl http://example.com) <(curl http://example.org) diff expects you to pass it two *files*, not processes, and the process substitution feature lets you provide it with those files, even though they are actually pipes backed by processes. Another example: curl http://example.com | \ tee >(curl -T. ftp://host1/a) >(curl -T. ftp://host2/b) tee duplicates its input and writes it into multiple files. It cannot start processes and works only with files, but in this example it sees two filenames (which are actually pipes to curl) and writes two copies of its input into them, essentially uploading the input to two ftp servers in parallel. And your "readarray foo < <(...)" is just a hack you do on top of it. You tell bash to replace <(...) with a filename, and the command becomes something like "readarray foo < /dev/fd/5". It doesn't really care where it does the substitution: in arguments to diff or after "<". Asking why bash inserts filename here is like asking why it runs "cat" when you type something like "foo | cat | cat | cat | bar" even though it's equivalent to "foo | bar". It does so because YOU told it to do so.
Race condition in read -t
Configuration Information [Automatically generated, do not change]: Machine: x86_64 OS: linux-gnu Compiler: x86_64-pc-linux-gnu-gcc Compilation CFLAGS: -DPROGRAM='bash' -DCONF_HOSTTYPE='x86_64' -DCONF_OSTYPE='linux-gnu' -DCONF_MACHTYPE='x86_64-pc-linux-gnu' -DCONF_VENDOR='pc' -DLOCALEDIR='/usr/share/locale' -DPACKAGE='bash' -DSHELL -DHAVE_CONFIG_H -I. -I./include -I. -I./include -I./lib -DDEFAULT_PATH_VALUE='/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin' -DSTANDARD_UTILS_PATH='/bin:/usr/bin:/sbin:/usr/sbin' -DSYS_BASHRC='/etc/bash/bashrc' -DSYS_BASH_LOGOUT='/etc/bash/bash_logout' -DNON_INTERACTIVE_LOGIN_SHELLS -DSSH_SOURCE_BASHRC -O2 -pipe -march=native -mtune=native uname output: Linux thinkpad 4.1.6-hardened-r1 #1 SMP Wed Aug 26 04:44:35 MSK 2015 x86_64 AMD A6-3400M APU with Radeon(tm) HD Graphics AuthenticAMD GNU/Linux Machine Type: x86_64-pc-linux-gnu Bash Version: 4.3 Patch Level: 42 Release Status: release Description: Function reset_alarm() in read.def first resets SIGALRM handler and then cancels alarm. Sometimes, SIGALRM comes between those 2 calls and crashes (sub)shell. Repeat-By: while sleep 0.00$RANDOM; do echo test; done | while true; do read -t 0.00$RANDOM; echo $REPLY; done (usually takes a few seconds to crash, sometimes minutes) Fix: Swap the lines in reset_alarm().