On Mon, Apr 23, 2012 at 04:56:09PM +0800, Clark Wang wrote: > When I revisit this 2 years old thread I don't understand why following > foo() function does not output the global var: > > $ cat foo.sh > var=global > foo() > { > local var=foo > unset var > echo foo: $var > } > bar_unset() > { > unset var > } > bar() > { > local var=bar > bar_unset > echo bar: $var > } > foo > bar > $ bash foo.sh > foo: > bar: global > $ > > In foo() it unsets its local var so why doesn't the subsequent $var refer > to the global var?
Well, the manual certainly doesn't give enough information to figure it out. unset [-fv] [name ...] For each name, remove the corresponding variable or function. If no options are supplied, or the -v option is given, each name refers to a shell variable. Read-only variables may not be unset. If -f is specified, each name refers to a shell function, and the function definition is removed. Each unset variable or function is removed from the environment passed to subsequent commands. If any of COMP_WORDBREAKS, RANDOM, SECONDS, LINENO, HISTCMD, FUNCNAME, GROUPS, or DIRSTACK are unset, they lose their special properties, even if they are subsequently reset. The exit status is true unless a name is readonly. Apparently there's a lot more going on than just "remove the corresponding variable or function". http://fvue.nl/wiki/Bash:_Unset says that unset will "traverse down the call-stack and unset variables repeatedly", which is fine, but that still doesn't explain what you're asking. So, here's my guess: when you unset a local variable within the same function where the variable was defined, bash assumes you explicitly want the variable to remain unset within that function. In foo(), you make a local var and then unset var. Bash believes you expect $var to be empty for that function. However, when you unset a variable from a different function where it's *not* locally defined, then unset traverses back through the dynamic scope stack of definitions for that variable, and whacks the topmost one. Thus, in bar_unset(), you call unset var, but there's no local copy of var, so it looks back through the stack, finds one in bar(), and gets rid of that one. Then the only remaining definition of var is the global one. So when you return to bar(), only the global one remains.