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/

Reply via email to