On 3/17/17 5:51 PM, Stephane Chazelas wrote: > Now, if that "split" functions is called from within a function > that declares $IFS local like: [...] > because after the "unset IFS", $IFS is not unset (which would > result in the default splitting behaviour) but set to ":" as it > was before "bar" ran "local IFS=."
This is how local variables work. Setting a local variable shadows any global with the same name; unsetting a local variable reveals the global variable (or really, because bash has dynamic scoping, the value at a previous scope) since there is no longer a local variable to shadow it. > > A simpler reproducer: > > $ bash -c 'f()(unset a; echo "$a"); g(){ local a=1; f;}; a=0; g' > 0 > > Or even with POSIX syntax: > > $ bash -c 'f()(unset a; echo "$a"); a=0; a=1 eval f' > 0 In this case, the unset unsets the variable provided in the builtin's `environment'. It's essentially the same thing. > > A work around is to change the "split" function to: > > split() ( > local IFS > unset -v IFS # default splitting > set -o noglob # disable glob > > set -- $1 # split+(no)glob > [ "$#" -eq 0 ] || printf '<%s>\n' "$@" > ) > > For some reason, in that case (when "local" and "unset" are > called in the same function context), unset does unset the > variable. There's special code in bash to preserve the locally-declared nature of a variable if you use local and unset in the same function scope. That's been in bash forever (at least as far back as bash-2.0, which is when I quit looking), for compatibility -- that's how ksh93 behaves -- and user expectations. Chet -- ``The lyf so short, the craft so long to lerne.'' - Chaucer ``Ars longa, vita brevis'' - Hippocrates Chet Ramey, UTech, CWRU c...@case.edu http://cnswww.cns.cwru.edu/~chet/