more changes to handle @ and * as associative array keys

This commit is contained in:
Chet Ramey
2021-05-13 14:49:18 -04:00
parent b304aabc92
commit a30f513fc4
35 changed files with 404 additions and 59 deletions
+65
View File
@@ -10247,3 +10247,68 @@ builtins/shopt.def
builtins/common.h
- expand_once_flag: extern declaration
5/10
----
doc/{bash.1,bashref.texi}
- note that case patterns undergo quote removal. Reported by
AlvinSeville7cf <alvinseville7cf@gmail.com>
5/11
----
builtins/bashgetopt.c
- list_optflags: flags associated with the word corresponding to
list_optarg, assuming list_optarg is a separate argument
builtins/bashgetopt.h
- list_optflags: extern declaration
builtins/set.def
- unset_builtin: set VFLAGS each time through the loop, since we take
whether or not the word has W_ARRAYREF set into account
- unset_builtin: don't pass VA_ALLOWALL to unbind_array_element for
now
test.c
- unary_test: in the -v case, use assoc_expand_once in the first call
to valid_array_reference ()
builtins/printf.def
- printf_builtin: only set VA_ONEWORD if the option argument to -v has
W_ARRAYREF set (look at list_optflags)
5/12
----
subst.c
- expand_array_subscript: don't quote @ or * in the expanded subscript
at all, even when they are the only character in the subscript. See
how this works out -- it might uncover places where we need to allow
`*' and `@' as subscripts where they are not allowed now
expr.c
- expr_bind_variable: pass ASS_ALLOWALLSUB to bind_int_variable so we
can allow (( A[@]=value )) when A is an existing associative array
arrayfunc.h
- AV_ATSTARKEYS: new flag value, means to accept a[@] and a[*] but
treat them as keys/expressions and not special values
arrayfunc.c
- array_value_internal: check AV_ATSTARKEYS and don't treat them as
ALL_ELEMENT_SUB values; they fall through to use as keys/indices
test.c
- unary_test: if -v is passed an array reference, add AV_ATSTARKEYS to
the flags passed to array_value so we treat @ and * as keys for an
existing associative array
5/13
----
subst.c
- expand_cond_word: if SPECIAL == 3 (arithmetic expression), dequote the
resulting WORD_LIST * as if special == 0, because we don't want to
quote the list for pattern matching. Report from
Adjudicator Darren <adjudicatordarren@protonmail.com>
+1
View File
@@ -1313,6 +1313,7 @@ tests/quotearray.tests f
tests/quotearray1.sub f
tests/quotearray2.sub f
tests/quotearray3.sub f
tests/quotearray4.sub f
tests/read.tests f
tests/read.right f
tests/read1.sub f
+5 -2
View File
@@ -1370,7 +1370,7 @@ array_value_internal (s, quoted, flags, rtype, indp)
int quoted, flags, *rtype;
arrayind_t *indp;
{
int len;
int len, isassoc;
arrayind_t ind;
char *akey;
char *retval, *t, *temp;
@@ -1389,9 +1389,12 @@ array_value_internal (s, quoted, flags, rtype, indp)
if (len == 0)
return ((char *)NULL); /* error message already printed */
isassoc = var && assoc_p (var);
/* [ */
akey = 0;
if (ALL_ELEMENT_SUB (t[0]) && t[1] == ']')
/* Backwards compatibility: we only change the behavior of A[@] and A[*]
for associative arrays, and the caller has to request it. */
if ((isassoc == 0 || (flags & AV_ATSTARKEYS) == 0) && ALL_ELEMENT_SUB (t[0]) && t[1] == ']')
{
if (rtype)
*rtype = (t[0] == '*') ? 1 : 2;
+7 -1
View File
@@ -33,12 +33,14 @@ extern int assoc_expand_once;
extern int array_expand_once;
/* Flags for array_value_internal and callers array_value/get_array_value */
#define AV_ALLOWALL 0x001
#define AV_ALLOWALL 0x001 /* treat a[@] like $@ and a[*] like $* */
#define AV_QUOTED 0x002
#define AV_USEIND 0x004
#define AV_USEVAL 0x008 /* XXX - should move this */
#define AV_ASSIGNRHS 0x010 /* no splitting, special case ${a[@]} */
#define AV_NOEXPAND 0x020 /* don't run assoc subscripts through word expansion */
#define AV_ONEWORD 0x040 /* not used yet */
#define AV_ATSTARKEYS 0x080 /* accept a[@] and a[*] but use them as keys, not special values */
/* Flags for valid_array_reference. Value 1 is reserved for skipsubscript().
Also used by unbind_array_element, which is currently the only function
@@ -94,7 +96,11 @@ extern SHELL_VAR *array_variable_part PARAMS((const char *, int, char **, int *)
#define AV_ALLOWALL 0
#define AV_QUOTED 0
#define AV_USEIND 0
#define AV_USEVAL 0
#define AV_ASSIGNRHS 0
#define AV_NOEXPAND 0
#define AV_ONEWORD 0
#define AV_ATSTARKEYS 0
#define VA_NOEXPAND 0
#define VA_ONEWORD 0
+14 -1
View File
@@ -39,6 +39,7 @@
static int sp;
char *list_optarg;
int list_optflags;
int list_optopt;
int list_opttype;
@@ -62,6 +63,7 @@ char *opts;
if (list == 0) {
list_optarg = (char *)NULL;
list_optflags = 0;
loptend = (WORD_LIST *)NULL; /* No non-option arguments */
return -1;
}
@@ -102,6 +104,7 @@ char *opts;
sp = 1;
}
list_optarg = NULL;
list_optflags = 0;
if (lcurrent)
loptend = lcurrent->next;
return('?');
@@ -113,6 +116,7 @@ char *opts;
/* We allow -l2 as equivalent to -l 2 */
if (lcurrent->word->word[sp+1]) {
list_optarg = lcurrent->word->word + sp + 1;
list_optflags = 0;
lcurrent = lcurrent->next;
/* If the specifier is `;', don't set optarg if the next
argument looks like another option. */
@@ -123,15 +127,18 @@ char *opts;
#endif
lcurrent = lcurrent->next;
list_optarg = lcurrent->word->word;
list_optflags = lcurrent->word->flags;
lcurrent = lcurrent->next;
} else if (*cp == ';') {
list_optarg = (char *)NULL;
list_optflags = 0;
lcurrent = lcurrent->next;
} else { /* lcurrent->next == NULL */
errstr[1] = c;
sh_needarg (errstr);
sp = 1;
list_optarg = (char *)NULL;
list_optflags = 0;
return('?');
}
sp = 1;
@@ -140,19 +147,24 @@ char *opts;
if (lcurrent->word->word[sp+1]) {
if (DIGIT(lcurrent->word->word[sp+1])) {
list_optarg = lcurrent->word->word + sp + 1;
list_optflags = 0;
lcurrent = lcurrent->next;
} else
} else {
list_optarg = (char *)NULL;
list_optflags = 0;
}
} else {
if (lcurrent->next && legal_number(lcurrent->next->word->word, (intmax_t *)0)) {
lcurrent = lcurrent->next;
list_optarg = lcurrent->word->word;
list_optflags = lcurrent->word->flags;
lcurrent = lcurrent->next;
} else {
errstr[1] = c;
sh_neednumarg (errstr);
sp = 1;
list_optarg = (char *)NULL;
list_optflags = 0;
return ('?');
}
}
@@ -164,6 +176,7 @@ char *opts;
lcurrent = lcurrent->next;
}
list_optarg = (char *)NULL;
list_optflags = 0;
}
return(c);
+1
View File
@@ -29,6 +29,7 @@
#define GETOPT_HELP -99
extern char *list_optarg;
extern int list_optflags;
extern int list_optopt;
extern int list_opttype;
+5
View File
@@ -980,6 +980,11 @@ builtin_bind_variable (name, value, flags)
SHELL_VAR *v;
#if defined (ARRAY_VARS)
/* Callers are responsible for calling this with array references that have
already undergone valid_array_reference checks.
Affected builtins: read, printf
To make this really work, needs additional downstream support, starting
with assign_array_element and array_variable_name. */
if (valid_array_reference (name, assoc_expand_once ? (VA_NOEXPAND|VA_ONEWORD) : 0) == 0)
v = bind_variable (name, value, flags);
else
+7 -4
View File
@@ -1,7 +1,7 @@
This file is printf.def, from which is created printf.c.
It implements the builtin "printf" in Bash.
Copyright (C) 1997-2020 Free Software Foundation, Inc.
Copyright (C) 1997-2021 Free Software Foundation, Inc.
This file is part of GNU Bash, the Bourne Again SHell.
@@ -267,11 +267,14 @@ printf_builtin (list)
case 'v':
vname = list_optarg;
#if defined (ARRAY_VARS)
arrayflags = assoc_expand_once ? (VA_NOEXPAND|VA_ONEWORD) : 0;
if (legal_identifier (vname) || valid_array_reference (vname, arrayflags))
arrayflags = assoc_expand_once ? VA_NOEXPAND : 0;
if (assoc_expand_once && (list_optflags & W_ARRAYREF))
arrayflags |= VA_ONEWORD; /* XXX - VA_NOEXPAND? */
retval = legal_identifier (vname) || valid_array_reference (vname, arrayflags);
#else
if (legal_identifier (vname))
retval = legal_identifier (vname);
#endif
if (retval)
{
vflag = 1;
if (vbsize == 0)
+14 -9
View File
@@ -835,7 +835,7 @@ unset_builtin (list)
WORD_LIST *list;
{
int unset_function, unset_variable, unset_array, opt, nameref, any_failed;
int global_unset_func, global_unset_var, vflags, valid_id;
int global_unset_func, global_unset_var, vflags, base_vflags, valid_id;
char *name, *tname;
unset_function = unset_variable = unset_array = nameref = any_failed = 0;
@@ -872,9 +872,7 @@ unset_builtin (list)
else if (unset_function && nameref)
nameref = 0;
#if defined (ARRAY_VARS)
vflags = assoc_expand_once ? (VA_NOEXPAND|VA_ONEWORD) : 0;
#endif
base_vflags = assoc_expand_once ? VA_NOEXPAND : 0;
while (list)
{
@@ -889,6 +887,16 @@ unset_builtin (list)
unset_function = global_unset_func;
unset_variable = global_unset_var;
#if defined (ARRAY_VARS)
vflags = base_vflags;
/* Don't require assoc_expand_once if we have an argument that's already
passed through valid_array_reference and been expanded once. That
doesn't protect it from normal expansions like word splitting, so
proper quoting is still required. */
if (list->word->flags & W_ARRAYREF)
vflags |= VA_ONEWORD|VA_NOEXPAND;
#endif
#if defined (ARRAY_VARS)
unset_array = 0;
/* XXX valid array reference second arg was 0 */
@@ -959,15 +967,12 @@ unset_builtin (list)
#if defined (ARRAY_VARS)
if (var && unset_array)
{
int tvflags;
tvflags = vflags;
#if 0 /* TAG:bash-5.2 */
if (shell_compatibility_level <= 51)
tvflags |= VA_ALLOWALL;
vflags |= VA_ALLOWALL;
#endif
/* Let unbind_array_element decide what to do with non-array vars */
tem = unbind_array_element (var, t, tvflags); /* XXX new third arg */
tem = unbind_array_element (var, t, vflags); /* XXX new third arg */
if (tem == -2 && array_p (var) == 0 && assoc_p (var) == 0)
{
builtin_error (_("%s: not an array variable"), var->name);
+3 -3
View File
@@ -5,12 +5,12 @@
.\" Case Western Reserve University
.\" chet.ramey@case.edu
.\"
.\" Last Change: Wed May 5 16:28:46 EDT 2021
.\" Last Change: Mon May 10 10:12:31 EDT 2021
.\"
.\" bash_builtins, strip all but Built-Ins section
.if \n(zZ=1 .ig zZ
.if \n(zY=1 .ig zY
.TH BASH 1 "2021 May 5" "GNU Bash 5.1"
.TH BASH 1 "2021 May 10" "GNU Bash 5.1"
.\"
.\" There's some problem with having a `@'
.\" in a tagged paragraph with the BSD man macros.
@@ -894,7 +894,7 @@ expansion, parameter and variable expansion, arithmetic expansion,
command substitution, process substitution and quote removal.
Each \fIpattern\fP examined is expanded using tilde
expansion, parameter and variable expansion, arithmetic expansion,
command substitution, and process substitution.
command substitution, process substitution, and quote removal.
If the
.B nocasematch
shell option is enabled, the match is performed without regard to the case
+4 -3
View File
@@ -1039,9 +1039,10 @@ Each clause must be terminated with @samp{;;}, @samp{;&}, or @samp{;;&}.
The @var{word} undergoes tilde expansion, parameter expansion, command
substitution, arithmetic expansion, and quote removal
(@pxref{Shell Parameter Expansion})
before matching is
attempted. Each @var{pattern} undergoes tilde expansion, parameter
expansion, command substitution, and arithmetic expansion.
before matching is attempted.
Each @var{pattern} undergoes tilde expansion, parameter expansion,
command substitution, arithmetic expansion, process substitution, and
quote removal.
There may be an arbitrary number of @code{case} clauses, each terminated
by a @samp{;;}, @samp{;&}, or @samp{;;&}.
+2 -2
View File
@@ -2,10 +2,10 @@
Copyright (C) 1988-2021 Free Software Foundation, Inc.
@end ignore
@set LASTCHANGE Wed May 5 16:29:06 EDT 2021
@set LASTCHANGE Mon May 10 10:12:46 EDT 2021
@set EDITION 5.1
@set VERSION 5.1
@set UPDATED 5 May 2021
@set UPDATED 10 May 2021
@set UPDATED-MONTH May 2021
+5
View File
@@ -54,6 +54,7 @@ char *fn;
write(2, "\n", 1);
return 1;
}
QUIT;
w = write(1, buf, n);
if (w != n) {
e = errno;
@@ -63,6 +64,7 @@ char *fn;
write(2, "\n", 1);
return 1;
}
QUIT;
}
return 0;
}
@@ -79,6 +81,7 @@ char **argv;
return (fcopy(0, "standard input"));
for (i = r = 1; i < argc; i++) {
QUIT;
if (argv[i][0] == '-' && argv[i][1] == '\0')
fd = 0;
else {
@@ -97,6 +100,7 @@ char **argv;
if (fd != 0)
close(fd);
}
QUIT;
return (r);
}
@@ -108,6 +112,7 @@ WORD_LIST *list;
int c, r;
v = make_builtin_argv(list, &c);
QUIT;
r = cat_main(c, v);
free(v);
+4
View File
@@ -415,10 +415,14 @@ cutfile (v, list, ops)
#endif
while ((n = zgetline (fd, &line, &llen, '\n', unbuffered_read)) != -1)
{
QUIT;
cutline (v, line, ops); /* can modify line */
}
if (fd > 0)
close (fd);
QUIT;
if (l)
l = l->next;
}
+3
View File
@@ -79,11 +79,13 @@ file_head (fp, cnt)
{
while ((ch = getc (fp)) != EOF)
{
QUIT;
if (putchar (ch) == EOF)
{
builtin_error ("write error: %s", strerror (errno));
return EXECUTION_FAILURE;
}
QUIT;
if (ch == '\n')
break;
}
@@ -141,6 +143,7 @@ head_builtin (list)
printf ("%s==> %s <==\n", opt ? "" : "\n", l->word->word);
opt = 0;
}
QUIT;
rval = file_head (fp, nline);
fclose (fp);
}
+5 -1
View File
@@ -59,7 +59,8 @@ _remove_directory(const char *dirname)
char *fname;
int fnsize;
#endif
QUIT;
if (*dp->d_name == '.' && (dp->d_name[1] == 0 || (dp->d_name[1] == '.' && dp->d_name[2] == 0)))
continue;
@@ -76,6 +77,7 @@ _remove_directory(const char *dirname)
#ifndef __GNUC__
free (fname);
#endif
QUIT;
}
closedir(dir);
@@ -98,6 +100,7 @@ rm_file(const char *fname)
if (unlink (fname) == 0)
return 0;
QUIT;
/* If FNAME is a directory glibc returns EISDIR but correct POSIX value
would be EPERM. If we get that error and FNAME is a directory and -r
was supplied, recursively remove the directory and its contents */
@@ -155,6 +158,7 @@ rm_builtin (list)
for (l = list; l; l = l->next)
{
QUIT;
if (rm_file(l->word->word) && force == 0)
rval = EXECUTION_FAILURE;
}
+5 -2
View File
@@ -3,7 +3,7 @@
/* See Makefile for compilation details. */
/*
Copyright (C) 1999-2009 Free Software Foundation, Inc.
Copyright (C) 1999-2021 Free Software Foundation, Inc.
This file is part of GNU Bash.
Bash is free software: you can redistribute it and/or modify
@@ -121,6 +121,7 @@ tee_builtin (list)
fl = fl->next;
fl->next = (FLIST *)NULL;
}
QUIT;
}
while ((nr = read(0, buf, TEE_BUFSIZE)) > 0)
@@ -137,6 +138,7 @@ tee_builtin (list)
break;
}
bp += nw;
QUIT;
}
while (n -= nw);
}
@@ -156,7 +158,8 @@ tee_builtin (list)
tee_flist = tee_flist->next;
free (fl);
}
QUIT;
return (rval);
}
+2 -1
View File
@@ -3,7 +3,7 @@
/* See Makefile for compilation details. */
/*
Copyright (C) 1999-2009 Free Software Foundation, Inc.
Copyright (C) 1999-2021 Free Software Foundation, Inc.
This file is part of GNU Bash.
Bash is free software: you can redistribute it and/or modify
@@ -55,6 +55,7 @@ tty_builtin (list)
list = loptend;
t = ttyname (0);
QUIT;
if (sflag == 0)
puts (t ? t : "not a tty");
return (t ? EXECUTION_SUCCESS : EXECUTION_FAILURE);
+1
View File
@@ -330,6 +330,7 @@ expr_bind_variable (lhs, rhs)
#if defined (ARRAY_VARS)
aflags = (assoc_expand_once && already_expanded) ? ASS_NOEXPAND : 0;
aflags |= ASS_ALLOWALLSUB; /* allow assoc[@]=value */
#else
aflags = 0;
#endif
BIN
View File
Binary file not shown.
+6 -11
View File
@@ -5,13 +5,13 @@
# Zi-You Dai <ioppooster@gmail.com>, 2008.
# Mingye Wang (Arthur2e5) <arthur200126@hotmail.com>, 2015.
# Wei-Lun Chao <bluebat@member.fsf.org>, 2015.
# Yi-Jyun Pan <pan93412@gmail.com>, 2018, 2019, 2020.
# Yi-Jyun Pan <pan93412@gmail.com>, 2018, 2019, 2020, 2021.
msgid ""
msgstr ""
"Project-Id-Version: bash 5.1\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2020-11-28 12:51-0500\n"
"PO-Revision-Date: 2020-12-08 06:39+0800\n"
"PO-Revision-Date: 2021-05-09 20:48+0800\n"
"Last-Translator: Yi-Jyun Pan <pan93412@gmail.com>\n"
"Language-Team: Chinese (traditional) <zh-l10n@lists.linux.org.tw>\n"
"Language: zh_TW\n"
@@ -20,7 +20,7 @@ msgstr ""
"Content-Transfer-Encoding: 8bit\n"
"X-Bugs: Report translation errors to the Language-Team address.\n"
"Plural-Forms: nplurals=1; plural=0;\n"
"X-Generator: Poedit 2.4.2\n"
"X-Generator: Poedit 2.4.3\n"
#: arrayfunc.c:66
msgid "bad array subscript"
@@ -144,7 +144,6 @@ msgid "only meaningful in a `for', `while', or `until' loop"
msgstr "僅在「for」,「while」, 或者「until」迴圈中有意義"
#: builtins/caller.def:136
#, fuzzy
msgid ""
"Returns the context of the current subroutine call.\n"
" \n"
@@ -158,15 +157,11 @@ msgstr ""
"回傳目前子呼叫的語境。\n"
" \n"
" 不帶有 EXPR 時,回傳「$line $filename」。帶有 EXPR 時,回傳\n"
" 「$line $subroutine $filename」;這個額外的資訊可以被用於提供\n"
" 堆疊追蹤。\n"
" 「$line $subroutine $filename」;提供堆疊追蹤時可以用到這個\n"
" 延伸資訊。\n"
" \n"
" EXPR 的值顯示了到目前呼叫框格需要回去多少個呼叫框格;頂部框格\n"
" 是第 0 框格。\n"
" \n"
" 結束狀態:\n"
" 除非 shell 不在執行一個 shell 函數或者 EXPR 無效,否則回傳結\n"
" 果為 0。"
" 是第 0 框格。"
#: builtins/cd.def:327
msgid "HOME not set"
+8 -5
View File
@@ -3696,6 +3696,13 @@ cond_expand_word (w, special)
dequote_list (l);
r = string_list (l);
}
else if (special == 3) /* arithmetic expression, Q_ARITH */
{
if (l->word)
word_list_remove_quoted_nulls (l); /* for now */
dequote_list (l);
r = string_list (l);
}
else
{
/* Need to figure out whether or not we should call dequote_escapes
@@ -10192,6 +10199,7 @@ expand_array_subscript (string, sindex, quoted, flags)
abstab[LBRACK] = abstab[RBRACK] = 1;
abstab['$'] = abstab['`'] = abstab['~'] = 1;
abstab['\\'] = abstab['\''] = 1;
/* We don't quote `@' or `*' in the subscript at all. */
}
/* string[si] == LBRACK */
@@ -10215,11 +10223,6 @@ itrace("expand_array_subscript: bad subscript string: `%s'", string+si);
exp = substring (string, si+1, ni);
t = expand_subscript_string (exp, quoted & ~(Q_ARITH|Q_DOUBLE_QUOTES));
free (exp);
/* Only quote `@' and `*' if they are the only character in the subscript */
if (ALL_ELEMENT_SUB (t[0]) && t[1] == '\0')
abstab['*'] = abstab['@'] = 1;
else
abstab['*'] = abstab['@'] = 0;
exp = sh_backslash_quote (t, abstab, 0);
free (t);
+10 -4
View File
@@ -632,16 +632,22 @@ unary_test (op, arg, flags)
case 'v':
#if defined (ARRAY_VARS)
if (valid_array_reference (arg, 0))
if (valid_array_reference (arg, assoc_expand_once ? VA_NOEXPAND : 0))
{
char *t;
int rtype, ret, flags;
int rtype, ret, aflags;
/* Let's assume that this has already been expanded once. */
/* XXX - TAG:bash-5.2 fix with corresponding fix to execute_cmd.c:
execute_cond_node() that passes TEST_ARRAYEXP in FLAGS */
flags = assoc_expand_once ? AV_NOEXPAND : 0;
t = array_value (arg, 0, flags, &rtype, (arrayind_t *)0);
aflags = assoc_expand_once ? AV_NOEXPAND : 0;
#if 0
/* TAG:bash-5.2 */
if (shell_compatibility_level > 51)
#endif
aflags |= AV_ATSTARKEYS;
t = array_value (arg, 0, aflags, &rtype, (arrayind_t *)0);
ret = t ? TRUE : FALSE;
if (rtype > 0) /* subscript is * or @ */
free (t);
+1 -1
View File
@@ -747,7 +747,7 @@ declare -A A=([$'\t']="2" ["*"]="2" [" "]="2" ["]"]="2" ["@"]="2" )
declare -A A=([$'\t']="2" ["*"]="2" [" "]="2" ["]"]="2" ["@"]="2" )
./array27.sub: line 52: A[]]: bad array subscript
declare -A A=([$'\t']="X" ["*"]="X" [" "]="X" ["@"]="X" )
./array27.sub: line 60: A[]]: bad array subscript
./array27.sub: line 60: printf: `A[]]': not a valid identifier
declare -A A=([$'\t']="X" ["*"]="X" [" "]="X" ["@"]="X" )
./array27.sub: line 68: declare: `A[]]=X': not a valid identifier
declare -A A=(["*"]="X" ["@"]="X" )
+1 -5
View File
@@ -199,11 +199,7 @@ declare -A hash=([key]="value1 value2" )
declare -A b=([")"]="" ["\""]="" ["]"]="" ["\\"]="" ["\`"]="" )
declare -A b=(["]"]="" ["\`"]="" )
declare -A dict=(["'"]="3" ["\""]="1" ["\\"]="4" ["\`"]="2" )
./assoc9.sub: line 36: unset: `dict[']': not a valid identifier
./assoc9.sub: line 36: unset: `dict["]': not a valid identifier
./assoc9.sub: line 36: unset: `dict[\]': not a valid identifier
./assoc9.sub: line 36: unset: `dict[`]': not a valid identifier
declare -A dict=(["'"]="3" ["\""]="1" ["\\"]="4" ["\`"]="2" )
declare -A dict=()
declare -A dict=(["'"]="3" ["\""]="1" ["\\"]="4" ["\`"]="2" )
declare -A dict=()
4
+6
View File
@@ -179,10 +179,16 @@ unset2
1
1
1
0
0
assoc A unset
array a
assoc A
array a
assoc B unset
array b unset
assoc B unset
array b unset
scalar 1
scalar 2
scalar 3 unset
+10 -1
View File
@@ -36,15 +36,25 @@ echo ${#a[@]}
typeset -A B
typeset -a b
echo ${#B[@]}
echo ${#b[@]}
scalar1=foo
scalar2=
# this now checks for A[@] treating @ as a valid key - post-bash-5.1
if [ -v A[@] ]; then echo assoc A; else echo assoc A unset; fi
if [ -v a[@] ]; then echo array a; else echo array a unset; fi
if [ ${#A[@]} -gt 0 ]; then echo assoc A; else echo assoc A unset; fi
if [ ${#a[@]} -gt 0 ]; then echo array a; else echo array a unset; fi
if [ -v B[@] ]; then echo assoc B; else echo assoc B unset; fi
if [ -v b[@] ]; then echo array b; else echo array b unset; fi
if [ ${#B[@]} -gt 0 ]; then echo assoc B; else echo assoc B unset; fi
if [ ${#b[@]} -gt 0 ]; then echo array b; else echo array b unset; fi
if [ -v scalar1[@] ]; then echo scalar 1; else echo scalar 1 unset; fi
if [ -v scalar2[@] ]; then echo scalar 2; else echo scalar 2 unset; fi
if [ -v scalar3[@] ]; then echo scalar 3; else echo scalar 3 unset; fi
@@ -71,4 +81,3 @@ echo scalar: ${#scalar3}
echo scalar: ${#scalar3[@]}
+2
View File
@@ -27,6 +27,8 @@ returns: 0
returns: 1
returns: 0
returns: 0
returns: 0
returns: 0
returns: 1
returns: 0
returns: 0
+7
View File
@@ -122,6 +122,13 @@ A=7
[[ $IVAR -eq A ]]
echo returns: $?
[[ "$IVAR" -eq "7" ]]
echo returns: $?
A=7
[[ "$IVAR" -eq "A" ]]
echo returns: $?
unset IVAR A
# more pattern matching tests
+38 -1
View File
@@ -44,7 +44,7 @@ declare -A assoc=(["\` echo >&2 foo\`"]="128" [0]="0" ["]"]="12" ["x],b[\$(echo
foo
0
0
./quotearray1.sub: line 67: 0\],b\[1: syntax error: invalid arithmetic operator (error token is "\],b\[1")
./quotearray1.sub: line 68: 0\],b\[1: syntax error: invalid arithmetic operator (error token is "\],b\[1")
declare -a array
0
0
@@ -56,6 +56,9 @@ declare -A aa=(["\$( echo 2>& date)"]="foo" )
foo
0
1
1
./quotearray1.sub: line 111: test: aa[$(echo: binary operator expected
2
declare -A a=([1]="1" [0]="0" [" "]="11" )
7
7
@@ -71,6 +74,8 @@ declare -A A=(["*"]="X" ["@"]="X" )
declare -A A=(["*"]="X" ["@"]="X" )
./quotearray2.sub: line 89: let: assoc[x],b[$(echo: bad array subscript (error token is "b[$(echo")
declare -A assoc
declare -A assoc=(["\$(echo foo)"]="1" )
0
declare -A assoc=(["\$var"]="value" )
declare -A assoc=(["\$var"]="value" )
declare -A assoc=(["\$var"]="value" )
@@ -80,5 +85,37 @@ declare -A a=(["\$(echo foo)"]="1" )
declare -A a=()
declare -A a=(["\$(echo foo)"]="1" )
declare -A assoc=(["!"]="bang" )
1
1
declare -A assoc=(["!"]="bang" ["@"]="at" )
declare -A assoc=(["!"]="bang" )
declare -a array=([0]="1" [1]="2" [2]="3")
./quotearray3.sub: line 93: declare: array: not found
./quotearray3.sub: line 97: declare: array: not found
declare -A assoc=(["*"]="star" ["!"]="bang" ["@"]="at" )
declare -A assoc=(["*"]="star" ["!"]="bang" )
declare -A assoc=(["!"]="bang" )
./quotearray4.sub: line 41: declare: assoc: not found
declare -A assoc=(["*"]="star" ["!"]="bang" ["@"]="at" )
declare -A assoc=(["*"]="star" ["!"]="bang" )
declare -A assoc=(["!"]="bang" )
declare -A assoc=(["*"]="star" ["!"]="bang" )
declare -A assoc=(["!"]="bang" )
star bang at
star bang at
0
0
0
1
1
declare -A assoc=(["*"]="star" ["!"]="bang" ["@"]=" key" )
===
1
1
declare -a array=([0]="1" [1]="2" [2]="3")
1 2 3
1 2 3
0
0
./quotearray4.sub: line 115: array[@]: bad array subscript
declare -a array=([0]="1" [1]="2" [2]="3")
+3
View File
@@ -155,3 +155,6 @@ echo $?
${THIS_SH} ./quotearray1.sub
${THIS_SH} ./quotearray2.sub
${THIS_SH} ./quotearray3.sub
# behavior of builtins with array subscripts @ and *
${THIS_SH} ./quotearray4.sub
+9
View File
@@ -23,6 +23,7 @@ key2='` echo >&2 foo`'
key3='~'
key4='7<(4+2)'
key5='$( echo 2>& date)'
key6='$(echo foo)'
[[ -n assoc[$key] ]]
declare -p assoc
@@ -102,4 +103,12 @@ echo $?
[[ -v aa[$key] ]]
echo $?
aa[$key6]=42
# this still performs expansion
test -v aa["$key6"]
echo $?
# should be an error
test -v aa[$key6]
echo $?
unset aa key
+11
View File
@@ -90,3 +90,14 @@ let assoc[$key]++
declare -p assoc
unset assoc
typeset -A assoc
at=@
key='$(echo foo)'
assoc[$key]=1
declare -p assoc
shopt -s assoc_expand_once
test -v assoc["$key"] ; echo $?
+23 -2
View File
@@ -66,11 +66,32 @@ assoc[!]=bang
unset -v assoc[$key]
typeset -p assoc
# this doesn't work yet
# this should check for assoc[@] and return 1
test -v assoc[$key]
echo $?
# this should too
[[ -v assoc[$key] ]]
echo $?
unset assoc
unset assoc array
declare -A assoc
declare -a array
assoc=([@]=at [!]=bang)
declare -p assoc
unset assoc[@]
declare -p assoc
array=(1 2 3)
declare -p array
# right now, this still unsets the entire array
unset array[@]
declare -p array
BASH_COMPAT=51
unset array[@]
declare -p array
+116
View File
@@ -0,0 +1,116 @@
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
# tests for builtins handling associative array keys `*' and `@', with some
# indexed array tests as well (backwards compatible)
# derived from test cases posted to bug-bash by myoga.murase@gmail.com
declare -A assoc
declare -a array
assoc[@]=at
assoc[*]=star
assoc[!]=bang
key=@
iref='array[@]'
aref='assoc[@]'
declare -p assoc
unset assoc[@]
declare -p assoc
unset assoc[*]
declare -p assoc
unset assoc
declare -p assoc
declare -A assoc
assoc[@]=at
assoc[*]=star
assoc[!]=bang
declare -p assoc
unset assoc["$key"]
declare -p assoc
unset assoc["*"]
declare -p assoc
assoc[@]=at assoc[*]=star
unset assoc['@']
declare -p assoc
unset assoc['*']
declare -p assoc
assoc[@]=at assoc[*]=star
echo ${!aref}
declare -n nref=$aref
echo ${nref}
unset -n nref
# for associative arrays, test -v treats @ and * as keys
test -v 'assoc[@]'
echo $?
test -v assoc[$key]
echo $?
[[ -v assoc[$key] ]]
echo $?
unset -v 'assoc[@]'
test -v 'assoc[@]'
echo $?
[[ -v assoc[@] ]]
echo $?
assoc[@]=at
printf -v assoc[@] "%10s" key
declare -p assoc
echo ===
array=()
test -v array[@]
echo $?
[[ -v array[@] ]]
echo $?
array=(1 2 3)
declare -p array
echo ${!iref}
declare -n nref=$iref
echo $nref
unset -n nref
# but for indexed arrays, test -v treats @ and * as standing for the entire array
test -v 'array[@]'
echo $?
[[ -v array[@] ]]
echo $?
printf -v array[@] "%-10s" key
declare -p array