- INTERNAL_DEBUG: use instead of calls to itrace protected by #ifdef
DEBUG
+ 12/26
+ -----
+lib/glob/glob.c
+ - glob_always_skip_dot_and_dotdot: initialize to 1 (enabled)
+
+builtins/shopt.def
+ - globskipdots: new shell option, exposes glob_always_skip_dot_and_dotdot
+doc/{bash.1,bashref.texi}
+ - globskipdots: document new shell option
+
+execute_cmd.c
+ - fix_arrayref_words: call valid_array_reference with 0 for third arg
+ because the words have not undergone any word expansions yet and
+ the quotes are still present. This makes things like
+ A=[\[]=set
+ unset A[\[]
+ work
+
+subst.c
+ - word_list_split: if a word undergoes word splitting but is not
+ changed, preserve any W_ARRAYREF flag into the new word. This makes
+ things like
+ rkey=']'
+ unset A[$rkey]
+ work because the unset builtin sees the W_ARRAYREF flag on its
+ argument
tests/assoc14.sub f
tests/assoc15.sub f
tests/assoc16.sub f
+tests/assoc17.sub f
tests/attr.tests f
tests/attr.right f
tests/attr1.sub f
tests/glob7.sub f
tests/glob8.sub f
tests/glob9.sub f
+tests/glob10.sub f
tests/glob.right f
tests/globstar.tests f
tests/globstar.right f
char **subp;
{
char *t;
- int r, len, isassoc;
+ int r, len, isassoc, ssflags;
SHELL_VAR *entry;
t = mbschr (name, '['); /* ] */
if (r == 0)
return 0;
+ ssflags = 0;
if (isassoc && ((flags & (VA_NOEXPAND|VA_ONEWORD)) == (VA_NOEXPAND|VA_ONEWORD)))
len = strlen (t) - 1;
else if (isassoc)
- len = skipsubscript (t, 0, flags&VA_NOEXPAND); /* VA_NOEXPAND must be 1 */
+ {
+ if (flags & VA_NOEXPAND)
+ ssflags |= 1;
+ len = skipsubscript (t, 0, ssflags);
+ }
else
/* Check for a properly-terminated non-null subscript. */
len = skipsubscript (t, 0, 0); /* arithmetic expression */
extern int autocd;
extern int glob_star;
extern int glob_asciirange;
+extern int glob_always_skip_dot_and_dotdot;
extern int lastpipe_opt;
extern int inherit_errexit;
extern int localvar_inherit;
{ "force_fignore", &force_fignore, (shopt_set_func_t *)NULL },
#endif
{ "globasciiranges", &glob_asciirange, (shopt_set_func_t *)NULL },
+ { "globskipdots", &glob_always_skip_dot_and_dotdot, (shopt_set_func_t *)NULL },
{ "globstar", &glob_star, (shopt_set_func_t *)NULL },
{ "gnu_errfmt", &gnu_error_format, (shopt_set_func_t *)NULL },
#if defined (HISTORY)
.\" Case Western Reserve University
.\" chet.ramey@case.edu
.\"
-.\" Last Change: Mon Nov 22 09:58:49 EST 2021
+.\" Last Change: Sun Dec 26 16:02:07 EST 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 November 22" "GNU Bash 5.2"
+.TH BASH 1 "2021 December 26" "GNU Bash 5.2"
.\"
.\" There's some problem with having a `@'
.\" in a tagged paragraph with the BSD man macros.
.SM
.BR "CONDITIONAL EXPRESSIONS" .
The words between the \fB[[\fP and \fB]]\fP do not undergo word splitting
-and filename expansion.
+and pathname expansion.
The shell performs tilde expansion, parameter and
variable expansion, arithmetic expansion, command substitution, process
substitution, and quote removal on those words
even if
.B dotglob
is set.
+If the
+.B globskipdots
+shell option is enabled, the filenames
+.B ``.''
+and
+.BR ``..''
+are never matched, even if the pattern begins with a
+.BR ``.'' .
When not matching pathnames, the
.B ``.''
character is not treated specially.
for a description of the
.BR nocaseglob ,
.BR nullglob ,
+.BR globskipdots ,
.BR failglob ,
and
.B dotglob
.BR B ,
and upper-case and lower-case ASCII characters will collate together.
.TP 8
+.B globskipdots
+If set, pathname expansion will never match the filenames
+.B ``.''
+and
+.BR ``..'' ,
+even if the pattern begins with a
+.BR ``.'' .
+This option is enabled by default.
+.TP 8
.B globstar
If set, the pattern \fB**\fP used in a pathname expansion context will
match all files and zero or more directories and subdirectories.
In order to match the filenames @samp{.} and @samp{..},
the pattern must begin with @samp{.} (for example, @samp{.?}),
even if @code{dotglob} is set.
+If the @code{globskipdots} shell option is enabled, the filenames
+@samp{.} and @samp{..} are never matched, even if the pattern begins
+with a @samp{.}.
When not matching filenames, the @samp{.} character is not treated specially.
When matching a filename, the slash character must always be
See the description of @code{shopt} in @ref{The Shopt Builtin},
for a description of the @code{nocaseglob}, @code{nullglob},
+@code{globskipdots},
@code{failglob}, and @code{dotglob} options.
The @env{GLOBIGNORE}
@samp{b} will not collate between @samp{A} and @samp{B},
and upper-case and lower-case ASCII characters will collate together.
+@item globskipdots
+If set, filename expansion will never match the filenames
+@samp{.} and @samp{..},
+even if the pattern begins with a @samp{.}.
+This option is enabled by default.
+
@item globstar
If set, the pattern @samp{**} used in a filename expansion context will
match all files and zero or more directories and subdirectories.
Copyright (C) 1988-2021 Free Software Foundation, Inc.
@end ignore
-@set LASTCHANGE Thu Dec 2 15:07:19 EST 2021
+@set LASTCHANGE Sun Dec 26 16:02:48 EST 2021
@set EDITION 5.2
@set VERSION 5.2
-@set UPDATED 2 December 2021
+@set UPDATED 26 December 2021
@set UPDATED-MONTH December 2021
for (w = wcmd->next; w; w = w->next)
{
- if (w->word && w->word->word && valid_array_reference (w->word->word, VA_NOEXPAND))
+ if (w->word && w->word->word && valid_array_reference (w->word->word, 0))
w->word->flags |= W_ARRAYREF;
}
}
/* Global variable controlling whether globbing ever returns . or ..
regardless of the pattern. If set to 1, no glob pattern will ever
match `.' or `..'. Disabled by default. */
-int glob_always_skip_dot_and_dotdot = 0;
+int glob_always_skip_dot_and_dotdot = 1;
/* Global variable to return to signify an error in globbing. */
char *glob_error_return;
: skip_double_quoted (ss, slen, ++i, 0);
/* no increment, the skip functions increment past the closing quote. */
}
- else if ((flags&1) == 0 && c == '$' && (string[i+1] == LPAREN || string[i+1] == LBRACE))
+ else if ((flags & 1) == 0 && c == '$' && (string[i+1] == LPAREN || string[i+1] == LBRACE))
{
si = i + 2;
if (string[si] == '\0')
w->word[0] = '\0';
tresult = make_word_list (w, (WORD_LIST *)NULL);
}
+#if defined (ARRAY_VARS)
+ /* pass W_ARRAYREF through for words that are not split and are
+ identical to the original word. */
+ if (tresult && tresult->next == 0 && t->next == 0 && (t->word->flags & W_ARRAYREF) && STREQ (t->word->word, tresult->word->word))
+ tresult->word->flags |= W_ARRAYREF;
+#endif
if (result == 0)
result = e = tresult;
else
dict=( "?" "quest" "*" "star" "'" "squote" "\$" "dol" "\"" "dquote" "\\" "bslash" "@" "at" "}" "rbrace" "{" "lbrace" "\`" "bquote" )
declare -A foo=([two]="" [one]="1" )
foo=( two "" one "1" )
-rparen dquote rbrace bs
-declare -A a=([")"]="rparen" ["\""]="dquote" ["]"]="rbrace" ["\\"]="bs" )
-")" "rparen" "\"" "dquote" "]" "rbrace" "\\" "bs"
-declare -A a=([")"]="rparen" ["\""]="dquote" ["]"]="rbrace" ["\\"]="bs" )
-declare -A a=([")"]="rparen" ["\""]="dquote" ["]"]="rbrace" ["\\"]="bs" )
-declare -A a=([")"]="rparen" ["\""]="dquote" ["]"]="rbrace" ["\\"]="bs" )
+rparen dquote rbracket bs
+declare -A a=([")"]="rparen" ["\""]="dquote" ["]"]="rbracket" ["\\"]="bs" )
+")" "rparen" "\"" "dquote" "]" "rbracket" "\\" "bs"
+declare -A a=([")"]="rparen" ["\""]="dquote" ["]"]="rbracket" ["\\"]="bs" )
+declare -A a=([")"]="rparen" ["\""]="dquote" ["]"]="rbracket" ["\\"]="bs" )
+declare -A a=([")"]="rparen" ["\""]="dquote" ["]"]="rbracket" ["\\"]="bs" )
declare -Arx foo=([two]="2" [three]="3" [one]="1" )
./assoc11.sub: line 90: foo: readonly variable
declare -A v1=(["1 2"]="3" )
stderr
42
42
+declare -A A=(["]"]="rbracket" ["["]="lbracket" )
+declare -A A=()
+declare -A A=(["]"]="rbracket" ["["]="lbracket" )
+declare -A A=()
+declare -A A=(["]"]="rbracket" ["["]="lbracket" )
+declare -A A=()
+declare -A A=(["]"]="rbracket" ["["]="lbracket" )
+declare -A A=()
+declare -A A=(["]"]="rbracket" ["["]="lbracket" )
+declare -A A=()
# tests with subscripts being expanded more than one in ${xxx} word expansions
${THIS_SH} ./assoc16.sub
+
+# tests with `[' and `]' subscripts and `unset'
+${THIS_SH} ./assoc17.sub
declare -p foo
echo foo=\( ${foo[@]@K} \)
-typeset -A a=( [\\]=bs [\"]=dquote [\)]=rparen [\]]=rbrace )
+typeset -A a=( [\\]=bs [\"]=dquote [\)]=rparen [\]]=rbracket )
echo ${a[@]}
declare -p a
+# 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/>.
+#
+
declare -A assoc=(hello world "key with spaces" "value with spaces" one 1 foo bar)
declare -p assoc
--- /dev/null
+# 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/>.
+#
+# test behavior with `unset' and `[' and ']' subscripts
+
+declare -A A
+rkey=']'
+lkey='['
+
+A[$rkey]=rbracket
+A[$lkey]=lbracket
+declare -p A
+
+unset A[$rkey]
+unset A[$lkey]
+declare -p A
+
+A["$rkey"]=rbracket
+A["$lkey"]=lbracket
+declare -p A
+
+unset A["$rkey"]
+unset A["$lkey"]
+declare -p A
+
+A[\]]=rbracket
+A[\[]=lbracket
+declare -p A
+
+unset A[\]]
+unset A[\[]
+declare -p A
+
+A[']']=rbracket
+A['[']=lbracket
+declare -p A
+
+unset A[']']
+unset A['[']
+declare -p A
+
+A["]"]=rbracket
+A["["]=lbracket
+declare -p A
+
+unset A["]"]
+unset A["["]
+declare -p A
a ab
a ab
a
-. ..
-. .. a.log
+*(.)
+a.log
*(foo)
*(foo|bar)
a.log
?(foo)
a.log
a.log
-. ..
-. ..
+*(foo).*
+*(foo|bar).*
a.log
a.log
.x .y .z
.x .y .z a b c
.x .y .z a b c
*
-.. .b a
-.. .b a
-a .. .b
-. .. .b
-. .. .b
-.. .b a
-.. .b a
-a .. .b
-. .. .b
-. .. .b
+.b a
+.b a
+a .b
+.b
+.b
+.b a
+.b a
+a .b
+.b
+.b
dotglob: .a .foo bar
@(.foo)
.foo
LC_CTYPE=C LC_COLLATE=C
shopt -s extglob dotglob
+shopt -u globskipdots # XXX - backwards compatibility
touch .foo bar .a
echo dotglob: .a .foo bar
a\\ 1*b*
é/*
é/*
+a aa b bb
+.a .aa .b .bb a aa b bb
+.a .aa .b .bb
+. .. .a .aa .b .bb
argv[1] = <a>
argv[2] = <abc>
argv[3] = <abd>
argv[3] = <abd>
argv[4] = <abe>
tmp/l1 tmp/l2 tmp/*4 tmp/l3
-./glob.tests: line 65: no match: tmp/*4
+./glob.tests: line 66: no match: tmp/*4
argv[1] = <bdir/>
argv[1] = <*>
argv[1] = <a*>
${THIS_SH} ./glob7.sub
${THIS_SH} ./glob8.sub
${THIS_SH} ./glob9.sub
+${THIS_SH} ./glob10.sub
MYDIR=$PWD # save where we are
--- /dev/null
+# 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/>.
+#
+
+# test basic behavior of globskipdots
+TDIR=/tmp/dotglob-$$
+
+{ mkdir $TDIR && cd $TDIR; } || exit 1
+
+touch a b aa bb .a .b .aa .bb
+
+echo *
+shopt -s dotglob
+echo *
+
+shopt -s globskipdots
+echo .*
+shopt -u globskipdots
+echo .*
+
+cd $OLDPWD
+rm -rf $TDIR
shopt -u failglob
shopt -s force_fignore
shopt -s globasciiranges
+shopt -s globskipdots
shopt -u globstar
shopt -u gnu_errfmt
shopt -u histappend
shopt -s extquote
shopt -s force_fignore
shopt -s globasciiranges
+shopt -s globskipdots
shopt -s hostcomplete
shopt -s interactive_comments
shopt -s patsub_replacement
--
./shopt.tests: line 106: shopt: xyz1: invalid shell option name
./shopt.tests: line 107: shopt: xyz1: invalid option name
+28c28
+< globskipdots off
+---
+> globskipdots on
expand_aliases on
expand_aliases on