Zsh Mailing List Archive
Messages sorted by:
Reverse Date,
Date,
Thread,
Author
[PATCH] Implement references to positional parameters
- X-seq: zsh-workers 54301
- From: Philippe Altherr <philippe.altherr@xxxxxxxxx>
- To: Zsh hackers list <zsh-workers@xxxxxxx>
- Subject: [PATCH] Implement references to positional parameters
- Date: Mon, 6 Apr 2026 18:22:37 +0200
- Arc-authentication-results: i=1; mx.google.com; arc=none
- Arc-message-signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20240605; h=to:subject:message-id:date:from:mime-version:dkim-signature; bh=8HZUmfbm6ZvzRRnS5OsIEOrFZR/ZY1yiGymLxUCzX48=; fh=BgAYDYpL6Ne/A5nWEMVJiHiBtrz8Imz3uf26RDwgQX4=; b=POscQmv8RJgBZklKivqX+5IFI6IkjNAiyZt6IFyJYXu91Bitwcvh/knelUAmR7zQzx JuSrJtWbta0kJBo4XdHZe9xaXbciOWG1PhukZV2BEUcq3tUHWTFs0QUa+DSTYwMAjtEX eaU6mYxnWhtJAx6GWO/LIAX2xMRPGl5+GmOcXanlQDph7+/S5kCXtRC7LsBjiBcpu7M9 FyTajfFm6bPYPihtS11LViERc/iaw8Zft7BKJ99z0yFH93ZpGcUC1PBABmv1igH+23/K 9/va/n9lS/EssSs8ekqboGerqfJmV0nHd/M7DioWAaJHXAfIFKnDAekshoJL+xTIdd9D Wg0g==; darn=zsh.org
- Arc-seal: i=1; a=rsa-sha256; t=1775492570; cv=none; d=google.com; s=arc-20240605; b=SXsjDXS0GUsIn2Ql1sjXvARV5JCYTe0VB59xt3eJX0mqYV0VgJBns4yrpVcWoXbkT1 JRN/BpYVzDrmjAeMWk4H7tSYmDb2KFBs9h9sMDfpKPrz2I6taHPFeM899k92EFwxgGW8 vNpUHKcgXIelK8bfooES21fkrnxznHVWl2hTYpq6Rf3i7V3CB8KDAHriTMfWzvK9vRJU UkcyhYquxBwQa21d5kzaMZHjPOxStg5roYg0ioMDV5fCBwoIVOF8LeBz9PuCEpawS5sx Ao2DzN2PqgVnccyC3leu2MZ4yQ995ZUaZFFobq88EqoINOXUOg1Eo3fzwHAlcgSdSvGu ii1w==
- Archived-at: <https://zsh.org/workers/54301>
- List-id: <zsh-workers.zsh.org>
References to positional parameters are currently accepted but they aren't implemented. Such references behave like ones to not-yet-defined variables. The patch fixes this. One can then define "typeset -n ref=2" and use "$ref" to obtain "$2" or "ref=foo" to do "2=foo". Unsetting "ref" with "unset ref" has the same effect as "2=()". Assigning "ref" with an array value is however not possible; there is no "ref" equivalent of "2=(...)".
Philippe
diff --git a/Src/builtin.c b/Src/builtin.c
index 7c095149d..83a52d3ab 100644
--- a/Src/builtin.c
+++ b/Src/builtin.c
@@ -3857,13 +3857,10 @@ bin_unset(char *name, char **argv, Options ops, int func)
for (pm = (Param) paramtab->nodes[i]; pm; pm = next) {
/* record pointer to next, since we may free this one */
next = (Param) pm->node.next;
- if ((!(pm->node.flags & PM_RESTRICTED) ||
- unset(RESTRICTED)) &&
- pattry(pprog, pm->node.nam)) {
- if (!OPT_ISSET(ops,'n') &&
- (pm->node.flags & PM_NAMEREF) && pm->u.str)
- unsetparam(pm->u.str);
- else
+ if (pattry(pprog, pm->node.nam)) {
+ if (OPT_ISSET(ops,'n') ||
+ ((pm = resolve_nameref(pm)) &&
+ !(pm->node.flags & PM_NAMEREF)))
unsetparam_pm(pm, 0, 1);
match++;
}
@@ -3912,10 +3909,7 @@ bin_unset(char *name, char **argv, Options ops, int func)
*/
if (!pm)
continue;
- else if ((pm->node.flags & PM_RESTRICTED) && isset(RESTRICTED)) {
- zerrnam(name, "%s: restricted", pm->node.nam);
- returnval = 1;
- } else if (ss) {
+ else if (ss) {
if ((pm->node.flags & PM_NAMEREF) &&
(!(pm = resolve_nameref(pm)) || pm->width)) {
/* warning? */
@@ -3959,22 +3953,11 @@ bin_unset(char *name, char **argv, Options ops, int func)
zerrnam(name, "%s: invalid element for unset", s);
returnval = 1;
}
- } else {
- if (!OPT_ISSET(ops,'n')) {
- int ref = (pm->node.flags & PM_NAMEREF);
- if (!(pm = resolve_nameref(pm)))
- continue;
- if (ref && pm->level < locallevel &&
- !(pm->node.flags & PM_READONLY)) {
- /* Just mark unset, do not remove from table */
- stdunsetfn(pm, 0);
- pm->node.flags |= PM_DECLARED;
- continue;
- }
- }
+ } else if (OPT_ISSET(ops,'n') ||
+ ((pm = resolve_nameref(pm)) &&
+ !(pm->node.flags & PM_NAMEREF)))
if (unsetparam_pm(pm, 0, 1))
returnval = 1;
- }
if (ss)
*ss = '[';
}
diff --git a/Src/params.c b/Src/params.c
index 461e02acf..516c6bcde 100644
--- a/Src/params.c
+++ b/Src/params.c
@@ -224,6 +224,8 @@ static const struct gsu_integer ttyidle_gsu =
static const struct gsu_scalar argzero_gsu =
{ argzerogetfn, argzerosetfn, nullunsetfn };
+static const struct gsu_scalar argn_gsu =
+{ argngetfn, argnsetfn, argnunsetfn };
static const struct gsu_scalar username_gsu =
{ usernamegetfn, usernamesetfn, stdunsetfn };
static const struct gsu_scalar dash_gsu =
@@ -484,6 +486,8 @@ static initparam argvparam_pm = IPDEF9("", &pparams, NULL, \
(zsfree((PM)->u.str), (PM)->u.str = (S)))
static Param argvparam;
+static Param *argnparams;
+static size_t argnparams_size;
/*
* Lists of references to nested variables ("Param" instances) indexed
@@ -499,6 +503,16 @@ static Param argvparam;
* times in the same list. Non of that is harmful as long as only
* instances that are still references referring to the ending scope
* are updated when the scope ends.
+ *
+ * The list corresponding to the global scope never receives any of
+ * the named references described above. Instead, it's used to track
+ * global parameters that were unset via a named reference while in a
+ * scope where they were hidden by a nested parameter with the same
+ * name. In such cases, the global parameter's Param instance can't be
+ * deleted as usual. Instead, it's marked as unset and added to the
+ * global scope's list. Each time a scope ends, the list is traversed
+ * and parameters that are still unset but no longer hidden are
+ * deleted.
*/
static LinkList *scoperefs = NULL;
static int scoperefs_num = 0;
@@ -846,6 +860,9 @@ createparamtable(void)
}
argvparam = (Param) &argvparam_pm;
+ argnparams = zshcalloc(8 * sizeof(Param));
+ argnparams_size = 8;
+ argnparams[0] = (Param) paramtab->getnode(paramtab, "0");
noerrs = 2;
@@ -3934,6 +3951,24 @@ unsetparam_pm(Param pm, int altflag, int exp)
(pm->node.flags & (PM_SPECIAL|PM_REMOVABLE)) == PM_SPECIAL)
return 0;
+ /*
+ * Global variables can only be deleted if they aren't hidden by a
+ * local one with the same name.
+ */
+ if (!pm->level &&
+ pm != (Param) (paramtab == realparamtab ?
+ /* getnode2() to avoid autoloading */
+ paramtab->getnode2(paramtab, pm->node.nam) :
+ paramtab->getnode(paramtab, pm->node.nam))) {
+ LinkList refs;
+ if (!scoperefs)
+ scoperefs = zshcalloc((scoperefs_num = 8) * sizeof(refs));
+ if (!scoperefs[0])
+ scoperefs[0] = znewlinklist();
+ zpushnode(scoperefs[0], pm);
+ return 0;
+ }
+
/* remove parameter node from table */
paramtab->removenode(paramtab, pm->node.nam);
@@ -4980,6 +5015,49 @@ argzerogetfn(UNUSED(Param pm))
return argzero;
}
+/* Function to get value for positional parameters */
+
+/**/
+static char *
+argngetfn(Param pm)
+{
+ return arrlen_gt(pparams, pm->u.val - 1) ?
+ pparams[pm->u.val - 1] : (char *) hcalloc(1);
+}
+
+/* Function to set value for positional parameters */
+
+/**/
+static void
+argnsetfn(Param pm, char *x)
+{
+ int len = arrlen(pparams);
+ int ppar = pm->u.val;
+ if (ppar <= len)
+ zsfree(pparams[ppar - 1]);
+ else if (x) {
+ int i;
+ pparams = (char **) zrealloc(pparams, sizeof(char *) * ppar + 1);
+ for (i = len; i < ppar - 1; i++)
+ pparams[i] = ztrdup("");
+ pparams[ppar] = 0;
+ }
+ if (x) {
+ pparams[ppar - 1] = ztrdup(x);
+ zsfree(x);
+ } else if (ppar <= len)
+ memmove(pparams + ppar - 1, pparams + ppar, (len - ppar + 1) * sizeof(char *));
+}
+
+/* Function to unset positional parameters */
+
+/**/
+static void
+argnunsetfn(Param pm, UNUSED(int exp))
+{
+ argnsetfn(pm, NULL);
+}
+
/* Function to get value for special parameter `HISTSIZE' */
/**/
@@ -5909,6 +5987,15 @@ endparamscope(void)
setscope(pm);
}
}
+ /* Delete unset global variables that were hidden at unset time */
+ if ((refs = scoperefs ? scoperefs[0] : NULL)) {
+ scoperefs[0] = NULL;
+ for (Param pm; refs && (pm = (Param)getlinknode(refs));) {
+ if ((pm->node.flags & PM_UNSET) && !(pm->node.flags & PM_DECLARED))
+ unsetparam_pm(pm, 1, 0);
+ }
+ freelinklist(refs, NULL);
+ }
unqueue_signals();
}
@@ -6368,6 +6455,23 @@ resolve_nameref_rec(Param pm, const Param stop, int keep_lastref)
pm = resolve_nameref_rec(pm, stop, keep_lastref);
ref->node.flags &= ~PM_TAGGED;
}
+ } else if (idigit(*refname)) {
+ int ppar = zstrtol(refname, NULL, 10);
+ if (ppar >= argnparams_size) {
+ size_t old_size = argnparams_size;
+ size_t new_size = argnparams_size = MAX(2 * old_size, ppar);
+ argnparams = zrealloc(argnparams, new_size * sizeof(Param));
+ memset(argnparams + old_size, 0,
+ (new_size - old_size) * sizeof(Param));
+ }
+ if (!(pm = argnparams[ppar])) {
+ pm = argnparams[ppar] = zshcalloc(sizeof(*pm));
+ pm->node.nam = zalloc(snprintf(NULL, 0, "%d", ppar) + 1);
+ sprintf(pm->node.nam, "%d", ppar);
+ pm->node.flags = PM_SCALAR | PM_SPECIAL;
+ pm->u.val = ppar;
+ pm->gsu.s = &argn_gsu;
+ }
} else if (keep_lastref)
pm = ref;
unqueue_signals();
diff --git a/Test/K01nameref.ztst b/Test/K01nameref.ztst
index 0b4475827..6ab3ddcb7 100644
--- a/Test/K01nameref.ztst
+++ b/Test/K01nameref.ztst
@@ -1026,15 +1026,15 @@ F:Checking for a bug in zmodload that affects later tests
typeset -p .K01.{scalar,assoc,array,integer,double,float,readonly}
unset .K01.{scalar,assoc,array,integer,double,float}
0:unset various types via nameref, including a readonly special
->typeset -g .K01.scalar
->typeset -g -A .K01.assoc
->typeset -g -a .K01.array
->typeset -g -i .K01.integer
->typeset -g -E .K01.double
->typeset -g -F .K01.float
>typeset -g -r .K01.readonly=RO
*?*read-only variable: ARGC
*?*read-only variable: .K01.readonly
+*?*no such variable: .K01.scalar
+*?*no such variable: .K01.assoc
+*?*no such variable: .K01.array
+*?*no such variable: .K01.integer
+*?*no such variable: .K01.double
+*?*no such variable: .K01.float
unset -n ref
unset one
@@ -1339,14 +1339,14 @@ F:previously this could create an infinite recursion and crash
edgelocal() ( local -n x=$1; typeset -p x; print -r $x )
edgeupper() ( local -nu x=$1; typeset -p x; print -r $x )
- for edge in argv ARGC \@ \* \# 0 1 01 \! \? - _
+ for edge in argv ARGC \@ \* \# 0 00 1 01 \! \? - _
do
edgelocal $edge
edgelocal "$edge""[1]"
edgeupper $edge
done
0:references to builtin specials
-F:Subscripting on 1 01 ! ? - should print first character but do not
+F:Subscripting on 00 1 01 ! ? - should print first character but do not
>typeset -n x=argv
>argv
>typeset -n x='argv[1]'
@@ -1359,12 +1359,16 @@ F:Subscripting on 1 01 ! ? - should print first character but do not
>edgelocal
>typeset -n x='0[1]'
>e
->typeset -n x=1
+>typeset -n x=00
+>edgelocal
+>typeset -n x='00[1]'
>
+>typeset -n x=1
+>1
>typeset -n x='1[1]'
>
>typeset -n x=01
->
+>01
>typeset -n x='01[1]'
>
>typeset -n x=!
@@ -1403,6 +1407,7 @@ F:Subscripting on 1 01 ! ? - should print first character but do not
?edgelocal: invalid name reference: #[1]
?edgeupper: invalid name reference: #
?edgeupper: invalid name reference: 0
+?edgeupper: invalid name reference: 00
?edgeupper: invalid name reference: 1
?edgeupper: invalid name reference: 01
@@ -1418,6 +1423,75 @@ F:$$[1] reference should print the first digit of $$ but prints nothing
>$$[1]
>$$
+ tst() {
+ typeset -n ref0=0 2>&1
+ typeset -n ref00=00 2>&1
+ typeset -n ref2=2 2>&1
+ typeset -n ref02=02 2>&1
+ echo ${(q)0} ${(q)*} - $ref0 - $ref00 - $ref2 - $ref02
+ ref0=TST
+ ref2=BBB
+ echo ${(q)0} ${(q)*} - $ref0 - $ref00 - $ref2 - $ref02
+ ref00=Tst
+ ref02=Bbb
+ echo ${(q)0} ${(q)*} - $ref0 - $ref00 - $ref2 - $ref02; typeset -p -- 0 00 2 02 2>&1
+ unset ref0
+ unset ref2
+ echo ${(q)0} ${(q)*} - $ref0 - $ref00 - $ref2 - $ref02; typeset -p -- 0 00 2 02 2>&1
+ ref0=tst
+ ref2=bbb
+ echo ${(q)0} ${(q)*} - $ref0 - $ref00 - $ref2 - $ref02; typeset -p -- 0 00 2 02 2>&1
+ { ref0=(TST TST) 2>&1 } always { TRY_BLOCK_ERROR=0 }
+ { ref2=(BBB BBB) 2>&1 } always { TRY_BLOCK_ERROR=0 }
+ echo ${(q)0} ${(q)*} - $ref0 - $ref00 - $ref2 - $ref02; typeset -p -- 0 00 2 02 2>&1
+ typeset -n ref5=5 2>&1
+ ref5=zzz
+ echo ${(q)0} ${(q)*}
+ unset ref2
+ echo ${(q)0} ${(q)*}
+ unset ref2
+ echo ${(q)0} ${(q)*}
+ unset ref2
+ echo ${(q)0} ${(q)*}
+ unset ref2
+ echo ${(q)0} ${(q)*}
+ unset ref2
+ echo ${(q)0} ${(q)*}
+ }
+ tst aaa bbb ccc
+ unfunction tst
+0:references to positional parameters
+>tst aaa bbb ccc - tst - tst - bbb - bbb
+>TST aaa BBB ccc - TST - TST - BBB - BBB
+>Tst aaa Bbb ccc - Tst - Tst - Bbb - Bbb
+>tst:typeset:11: no such variable: 00
+>tst:typeset:11: no such variable: 2
+>tst:typeset:11: no such variable: 02
+>typeset -g 0=Tst
+>Tst aaa ccc - Tst - Tst - ccc - ccc
+>tst:typeset:14: no such variable: 00
+>tst:typeset:14: no such variable: 2
+>tst:typeset:14: no such variable: 02
+>typeset -g 0=Tst
+>tst aaa bbb - tst - tst - bbb - bbb
+>tst:typeset:17: no such variable: 00
+>tst:typeset:17: no such variable: 2
+>tst:typeset:17: no such variable: 02
+>typeset -g 0=tst
+>tst:18: 0: attempt to assign array value to non-array
+>tst:19: 2: attempt to assign array value to non-array
+>tst aaa bbb - tst - tst - bbb - bbb
+>tst:typeset:20: no such variable: 00
+>tst:typeset:20: no such variable: 2
+>tst:typeset:20: no such variable: 02
+>typeset -g 0=tst
+>tst aaa bbb '' '' zzz
+>tst aaa '' '' zzz
+>tst aaa '' zzz
+>tst aaa zzz
+>tst aaa
+>tst aaa
+
#
# The following tests are run in interactive mode, using PS1 as an
# assignable special with side-effects. This crashed at one time.
@@ -1933,6 +2007,257 @@ F:converting from association/array to string should work here too
># d:reference to not-yet-defined - local - ref1
>typeset -i var=42
+ test-unset() {
+ typeset var0=foo
+ typeset -n ref1=var0 ref2=ref1
+ typeset cmd=(unset $@); echo "#" $cmd; $cmd
+ typeset -p var0 ref1 ref2
+ }
+ test-unset -n ref1
+ test-unset -n ref2
+ test-unset -n -m ref1
+ test-unset -n -m ref2
+ unfunction test-unset
+0:unsetting references with -n unsets the references
+># unset -n ref1
+>typeset var0=foo
+>typeset -n ref2=ref1
+># unset -n ref2
+>typeset var0=foo
+>typeset -n ref1=var0
+># unset -n -m ref1
+>typeset var0=foo
+>typeset -n ref2=ref1
+># unset -n -m ref2
+>typeset var0=foo
+>typeset -n ref1=var0
+
+ test-unset() {
+ typeset var0=foo
+ typeset -n ref1=var0 ref2=ref1
+ typeset cmd=(unset $@); echo "#" $cmd; $cmd
+ typeset -p var0 ref1 ref2
+ }
+ test-unset ref1
+ test-unset ref2
+ test-unset -m ref1
+ test-unset -m ref2
+ unfunction test-unset
+0:unsetting references without -n unsets the referred parameters
+># unset ref1
+>typeset -n ref1=var0
+>typeset -n ref2=ref1
+># unset ref2
+>typeset -n ref1=var0
+>typeset -n ref2=ref1
+># unset -m ref1
+>typeset -n ref1=var0
+>typeset -n ref2=ref1
+># unset -m ref2
+>typeset -n ref1=var0
+>typeset -n ref2=ref1
+
+ test-unset() {
+ typeset var0=12345
+ typeset -n ref1=var0 ref2=ref1
+ typeset cmd=(unset $@); echo "#" $cmd; $cmd
+ typeset -p var0
+ }
+ test-unset ref1"[3]"
+ test-unset ref2"[3]"
+ test-unset -n ref1"[3]"
+ test-unset -n ref2"[3]"
+ unfunction test-unset
+0:unsetting subscripted references unsets the referred elements
+># unset ref1[3]
+>typeset var0=1245
+># unset ref2[3]
+>typeset var0=1245
+># unset -n ref1[3]
+>typeset var0=1245
+># unset -n ref2[3]
+>typeset var0=1245
+
+ test-unset() {
+ typeset -r var=foo
+ typeset -n ref=var
+ typeset cmd=(unset $@); echo "#" $cmd; { $cmd 2>&1 } always { TRY_BLOCK_ERROR=0 }
+ typeset -p var
+ }
+ test-unset var
+ test-unset -m var
+ test-unset ref
+ test-unset -m ref
+ test-unset var"[2]"
+ test-unset ref"[2]"
+ test-unset -n ref"[2]"
+ unfunction test-unset
+0:unsetting read-only parameter triggers an error
+># unset var
+>test-unset:3: read-only variable: var
+>typeset -r var=foo
+># unset -m var
+>test-unset:3: read-only variable: var
+>typeset -r var=foo
+># unset ref
+>test-unset:3: read-only variable: var
+>typeset -r var=foo
+># unset -m ref
+>test-unset:3: read-only variable: var
+>typeset -r var=foo
+># unset var[2]
+>test-unset:3: read-only variable: var
+>typeset -r var=foo
+># unset ref[2]
+>test-unset:3: read-only variable: var
+>typeset -r var=foo
+># unset -n ref[2]
+>test-unset:3: read-only variable: var
+>typeset -r var=foo
+
+ test-unset() (
+ setopt restricted
+ typeset -n ifs=IFS
+ typeset cmd=(unset $@); echo "#" $cmd; { $cmd 2>&1 } always { TRY_BLOCK_ERROR=0 }
+ typeset -p IFS
+ )
+ test-unset IFS
+ test-unset -m IFS
+ test-unset ifs
+ test-unset -m ifs
+ test-unset IFS"[2]"
+ test-unset ifs"[2]"
+ test-unset -n ifs"[2]"
+ unfunction test-unset
+0:unsetting restricted parameter triggers an error
+># unset IFS
+>test-unset:3: IFS: restricted
+>typeset -g IFS=$' \t\n\C-@'
+># unset -m IFS
+>test-unset:3: IFS: restricted
+>typeset -g IFS=$' \t\n\C-@'
+># unset ifs
+>test-unset:3: IFS: restricted
+>typeset -g IFS=$' \t\n\C-@'
+># unset -m ifs
+>test-unset:3: IFS: restricted
+>typeset -g IFS=$' \t\n\C-@'
+># unset IFS[2]
+>test-unset:3: IFS: restricted
+>typeset -g IFS=$' \t\n\C-@'
+># unset ifs[2]
+>test-unset:3: IFS: restricted
+>typeset -g IFS=$' \t\n\C-@'
+># unset -n ifs[2]
+>test-unset:3: IFS: restricted
+>typeset -g IFS=$' \t\n\C-@'
+
+ test-unset() {
+ typeset -n ref1 ref2=ref1
+ typeset cmd=(unset $@); echo "#" $cmd; $cmd
+ typeset -p ref1 ref2
+ }
+ test-unset ref1
+ test-unset ref2
+ test-unset -m ref1
+ test-unset -m ref2
+ unfunction test-unset
+0:unsetting placeholder references or their referents has no effect
+># unset ref1
+>typeset -n ref1
+>typeset -n ref2=ref1
+># unset ref2
+>typeset -n ref1
+>typeset -n ref2=ref1
+># unset -m ref1
+>typeset -n ref1
+>typeset -n ref2=ref1
+># unset -m ref2
+>typeset -n ref1
+>typeset -n ref2=ref1
+
+ test-unset() {
+ typeset -n ref1=undefined ref2=ref1
+ typeset cmd=(unset $@); echo "#" $cmd; $cmd
+ typeset -p ref1 ref2
+ }
+ typeset -p undefined 2>&1
+ test-unset ref1
+ test-unset ref2
+ test-unset -m ref1
+ test-unset -m ref2
+ unfunction test-unset
+0:unsetting references to not-yet-defined variables or their referents has no effect
+>(eval):typeset:6: no such variable: undefined
+># unset ref1
+>typeset -n ref1=undefined
+>typeset -n ref2=ref1
+># unset ref2
+>typeset -n ref1=undefined
+>typeset -n ref2=ref1
+># unset -m ref1
+>typeset -n ref1=undefined
+>typeset -n ref2=ref1
+># unset -m ref2
+>typeset -n ref1=undefined
+>typeset -n ref2=ref1
+
+ test-unset() {
+ typeset -n refg1=g1 refl1=l1
+ () {
+ typeset -g g1=glb1 g2=glb2
+ typeset l1=lcl1 l2=lcl2
+ () {
+ typeset -n refg2=g2 refl2=l2
+ typeset cmd=(unset $@ refg1 refg2 refl1 refl2); echo "#" $cmd; $cmd
+ } $@
+ typeset -p g1 g2 l1 l2 2>&1
+ } $@
+ unset g1 g2
+ }
+ test-unset
+ test-unset -m
+ unfunction test-unset
+0:unsetting references referring to parameters in enclosing scopes unsets the parameters
+># unset refg1 refg2 refl1 refl2
+>(anon):typeset:7: no such variable: g1
+>(anon):typeset:7: no such variable: g2
+># unset -m refg1 refg2 refl1 refl2
+>(anon):typeset:7: no such variable: g1
+>(anon):typeset:7: no such variable: g2
+
+ test-unset() {
+ typeset -g g=glb
+ typeset l=lcl
+ typeset -n refg=g refl=l
+ () {
+ typeset g=hide-g
+ typeset l=hide-l
+ typeset cmd=(unset $@ refg refl); echo "#" $cmd; $cmd
+ echo "# inner scope"
+ typeset -p g l 2>&1
+ } $@
+ echo "# outer scope"
+ typeset -p g l 2>&1
+ unset g
+ }
+ test-unset
+ test-unset -m
+ unfunction test-unset
+0:unsetting references referring to hidden parameters unsets the hidden parameters
+># unset refg refl
+># inner scope
+>typeset g=hide-g
+>typeset l=hide-l
+># outer scope
+>test-unset:typeset:12: no such variable: g
+># unset -m refg refl
+># inner scope
+>typeset g=hide-g
+>typeset l=hide-l
+># outer scope
+>test-unset:typeset:12: no such variable: g
+
typeset -n ref1
typeset -n ref2
typeset -n ref3=ref2
Messages sorted by:
Reverse Date,
Date,
Thread,
Author