Re: Dynamic variable failure & equiv-const strings compare unequal

2015-10-22 Thread Oleg Popov
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

2015-10-22 Thread Oleg Popov
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?

2015-10-17 Thread Oleg Popov
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

2015-08-28 Thread Oleg Popov
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().