3

I can't explain the following behavior of unset:

#!/bin/bash

my_unset() { unset "$@"; }

fn1() { local var;    unset var; var=1; }
fn2() { local var; my_unset var; var=2; }

var=0

fn1; echo "$var"
fn2; echo "$var"
0
2

edit: I would expect the result to be 1 2

It behaves that way on bash 3/4/5, is it a bug?


update

Here's an other example that shows that using my_unset doesn't make the variable global; it only removes the local variable from the current context:

#!/bin/bash

my_unset() { unset "$@"; }

fn1() { local var; my_unset var; var=1; }
fn2() { local var; fn1; echo "[fn2] var=$var"; }

var=0
fn2
echo "[global] var=$var"
[fn2] var=1
[global] var=0
Fravadona
  • 13,917
  • 1
  • 23
  • 35
  • Doing the unset in another function is somehow removing the localness of the variable. – Barmar Nov 11 '22 at 23:41
  • @Barmar Yes, but it doesn't make it a global variable necessarily; I'll add an other example to the question. – Fravadona Nov 11 '22 at 23:45
  • Have you searched the bash bug list? – Barmar Nov 11 '22 at 23:45
  • @Barmar Not yet; that would be a very long standing bug – Fravadona Nov 11 '22 at 23:46
  • 2
    I wonder if the output should be `1 2`. `local` "creates a variable", then `unset` "removes the variable", so `var=1` should refer to var at global scope. `localvar_unset` changes the behavior to `0 0`. There is also this in docs `If the unset acts on a variable at a previous scope, any instance of a variable with that name that had been shadowed will become visible`, maybe this is expected behavior, if you unset in the current scope, it remains local. – KamilCuk Nov 11 '22 at 23:48
  • @KamilCuk `localvar_unset` was added in bash 5. Apparently older versions act as if it's set. – Barmar Nov 11 '22 at 23:53

1 Answers1

3

See Chet's answer back in year 2012:

Back a number of years ago (16, to be exact), bash behaved like you expect. Between bash-1.14 and bash-2.0, I changed it in response to a number of bug reports that complained that a variable declared local in a function wasn't local when assigned a value in the function after being unset. Bash keeps a placeholder in the function's variable context so subsequent references to that unset variable don't traverse back through the call chain. This placeholder affects functions called by the function unsetting the local variable in the way you would expect dynamic scoping to work.

This only affects the current function, though: an unset issued from farther down the call chain, as you discovered, will unset the local variable without creating a placeholder.

pynexj
  • 19,215
  • 5
  • 38
  • 56