The patch below addresses the following three issues:
------------------------------

Doing unset -n n[0] actually unsets the target variable

$ v=(0 1); declare -n n=v
$ unset -n n[0]
$ declare -p n vdeclare -n n="v"
bash: declare: v: not found

------------------------------

Unsetting namerefs that are array references does not work

$ v=(0 1); declare -n n=v[1]
$ unset n
$ declare -p n vdeclare -n n="v[1]"declare -a v=([0]="0" [1]="1")

------------------------------

Same as with no options, unset -n will search for functions if it doesn’t
find a variable. If the nameref is invisble, it will unset any function
with the same name instead of the nameref.

While this might meet the posix requirement of “if neither -f nor -v…” I
suspect it would make more sense to follow the behavior as specified in the
bash docs

Without options, unset first tries to unset a variable, and if that fails,
tries to unset a function.

$ unset -n n; declare -n n; n() { :; }
$ unset -n n
$ declare -p n; declare -F ndeclare -n n

------------------------------

It’s also the case that if a function has a name that is also a valid array
reference, unset with no options will not find it and unset -f must be
used, but this seems reasonable.
------------------------------

diff --git a/builtins/set.def b/builtins/set.def
index 8f74f0e..c563fe7 100644--- a/builtins/set.def+++ b/builtins/set.def
@@ -808,7 +808,7 @@ unset_builtin (list)
 {
   int unset_function, unset_variable, unset_array, opt, nameref, any_failed;
   int global_unset_func, global_unset_var;-  char *name;+  char *name, *tname;

   unset_function = unset_variable = unset_array = nameref = any_failed = 0;
   global_unset_func = global_unset_var = 0;
@@ -859,7 +859,7 @@ unset_builtin (list)

 #if defined (ARRAY_VARS)
       unset_array = 0;-      if (!unset_function &&
valid_array_reference (name, 0))+      if (!unset_function && nameref
== 0 && valid_array_reference (name, 0))
        {
          t = strchr (name, '[');
          *t++ = '\0';
@@ -897,7 +897,7 @@ unset_builtin (list)
         find a function after unsuccessfully searching for a variable,
         note that we're acting on a function now as if -f were
         supplied.  The readonly check below takes care of it. */-
 if (var == 0 && unset_variable == 0 && unset_function == 0)+      if
(var == 0 && unset_variable == 0 && unset_function == 0 && nameref ==
0)
        {
          if (var = find_function (name))
            unset_function = 1;
@@ -932,7 +932,20 @@ unset_builtin (list)
       if (var == 0 && nameref == 0 && unset_function == 0)
        {
          var = find_variable_last_nameref (name, 0);-         tem =
(var && nameref_p (var)) ? unbind_variable (nameref_cell (var)) :
unbind_variable (name);+     if (var && nameref_p (var))+#if defined
(ARRAY_VARS)+       if (valid_array_reference (nameref_cell (var),
0))+         {+           tname = savestring(nameref_cell (var));+
      var = array_variable_part(tname, &t, 0);+           if (var)+
         tem = unbind_array_element (array_variable_part (tname, &t,
0), t);+         }+       else+#endif /* ARRAY_VARS */+         tem =
unbind_variable (nameref_cell (var));+     else+       tem =
unbind_variable (name);
        }
       else
        tem = unset_function ? unbind_func (name) : (nameref ?
unbind_nameref (name) : unbind_variable (name));
@@ -941,7 +954,7 @@ unset_builtin (list)
         is specified, the name refers to a variable; if a variable by
         that name does not exist, a function by that name, if any,
         shall be unset.'' */-      if (tem == -1 && unset_function ==
0 && unset_variable == 0)+      if (tem == -1 && unset_function == 0
&& unset_variable == 0 && nameref == 0)
        tem = unbind_func (name);

       name = list->word->word;         /* reset above for namerefs */

​

Attachment: unset_nameref_subscripts.patch
Description: Binary data

Reply via email to