From: Chet Ramey Date: Mon, 24 Nov 2025 14:51:15 +0000 (-0500) Subject: fix expansion of $* and $@ in contexts where word splitting is not performed to be... X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=4e705ed53ac364ee110f0b2fbeeab9d3301fcb6b;p=thirdparty%2Fbash.git fix expansion of $* and $@ in contexts where word splitting is not performed to be more consistent across different word expansions; fix pathname canonicalization when setting $BASH --- diff --git a/CWRU/CWRU.chlog b/CWRU/CWRU.chlog index 6698b837..8580314b 100644 --- a/CWRU/CWRU.chlog +++ b/CWRU/CWRU.chlog @@ -12253,3 +12253,32 @@ sig.c doc/bash.1,doc/bashref.texi - fix some options typeset in the wrong font Report and patch from Grisha Levit + +subst.c + - list_remove_pattern,parameter_list_remove_pattern,array_remove_pattern, + parameter_brace_remove_pattern: take an additional PFLAGS argument + from the PFLAGS passed to parameter_brace_expand + - list_remove_pattern: pass PFLAGS to string_list_pos_params so it can + get the right expansion of `@' and `*' + Report by Emanuele Torre + + 11/18 + ----- +variables.c + - get_bash_name: only call sh_canonpath on the directory portion of + the full pathname to the current executable; it only works on + directories. Then glue the return value and the trailing component + together to get the full pathname + Report from Stan Marsh + + 11/20 + ----- +subst.c + - parameter_list_transform,array_transform,list_transform: add an + extra PFLAGS argument, passed down from parameter_brace_transform + - list_transform,array_transform: pass PFLAGS to string_list_pos_params + so it can get the right expansion of `@' and `*' + This makes all the quoted and unquoted expansions of `@' consistent + when they are expanded in a context that will not perform word + splitting + Report by Emanuele Torre diff --git a/MANIFEST b/MANIFEST index 7f965be5..d1b00de7 100644 --- a/MANIFEST +++ b/MANIFEST @@ -1204,6 +1204,7 @@ tests/exp10.sub f tests/exp11.sub f tests/exp12.sub f tests/exp13.sub f +tests/exp14.sub f tests/exportfunc.tests f tests/exportfunc.right f tests/exportfunc1.sub f diff --git a/builtins/help.def b/builtins/help.def index f6db8a95..f2a975bc 100644 --- a/builtins/help.def +++ b/builtins/help.def @@ -135,7 +135,7 @@ help_builtin (WORD_LIST *list) globpat = glob_pattern_p (pattern); if (globpat) - printf (_("Shell commands matching pattern '%s':\n\n"), pattern); + printf (_("Shell commands matching pattern '%s':\n"), pattern); for (pass = 1, this_found = 0; pass < 3; pass++) { @@ -153,6 +153,8 @@ help_builtin (WORD_LIST *list) if (m) { + if (globpat && this_found == 0) + putchar ('\n'); this_found = 1; match_found++; if (dflag) diff --git a/subst.c b/subst.c index 34754189..bdbafac8 100644 --- a/subst.c +++ b/subst.c @@ -299,23 +299,23 @@ static int match_pattern (char *, char *, int, char **, char **); static int getpatspec (int, const char *); static char *getpattern (char *, int, int); static char *variable_remove_pattern (char *, char *, int, int); -static char *list_remove_pattern (WORD_LIST *, char *, int, int, int); -static char *parameter_list_remove_pattern (int, char *, int, int); +static char *list_remove_pattern (WORD_LIST *, char *, int, int, int, int); +static char *parameter_list_remove_pattern (int, char *, int, int, int); #ifdef ARRAY_VARS -static char *array_remove_pattern (SHELL_VAR *, char *, int, int, int); +static char *array_remove_pattern (SHELL_VAR *, char *, int, int, int, int); #endif -static char *parameter_brace_remove_pattern (char *, char *, array_eltstate_t *, char *, int, int, int); +static char *parameter_brace_remove_pattern (char *, char *, array_eltstate_t *, char *, int, int, int, int); static char *string_var_assignment (SHELL_VAR *, char *); #if defined (ARRAY_VARS) static char *array_var_assignment (SHELL_VAR *, int, int, int); #endif -static char *pos_params_assignment (WORD_LIST *, int, int); +static char *pos_params_assignment (WORD_LIST *, int, int, int); static char *string_transform (int, SHELL_VAR *, char *); -static char *list_transform (int, SHELL_VAR *, WORD_LIST *, int, int); -static char *parameter_list_transform (int, int, int); +static char *list_transform (int, SHELL_VAR *, WORD_LIST *, int, int, int); +static char *parameter_list_transform (int, int, int, int); #if defined ARRAY_VARS -static char *array_transform (int, SHELL_VAR *, int, int); +static char *array_transform (int, SHELL_VAR *, int, int, int); #endif static char *parameter_brace_transform (char *, char *, array_eltstate_t *, char *, int, int, int, int); static int valid_parameter_transform (const char *); @@ -3045,6 +3045,7 @@ string_list_dollar_at (WORD_LIST *list, int quoted, int flags) string_list as appropriate. */ /* This needs to fully understand the additional contexts where word splitting does not occur (W_ASSIGNRHS, etc.) */ +/* XXX - does this need to handle (pflags & PF_NOSPLIT2)? */ char * string_list_pos_params (int pchar, WORD_LIST *list, int quoted, int pflags) { @@ -3086,9 +3087,18 @@ string_list_pos_params (int pchar, WORD_LIST *list, int quoted, int pflags) else if (pchar == '@' && quoted == 0 && ifs_is_null) /* XXX */ ret = string_list_dollar_at (list, quoted, 0); /* Posix interp 888 */ else if (pchar == '@' && quoted == 0 && (pflags & PF_ASSIGNRHS)) + /* XXX - param_expand uses quoted|Q_DOUBLE_QUOTES for this case, but + that quotes the escapes. We could use string_list_internal with " " + as the second argument. */ ret = string_list_dollar_at (list, quoted, pflags); /* Posix interp 888 */ else if (pchar == '@') +#if 0 + /* XXX - param_expand uses string_list_dollar_at() for this case. */ + /* string_list_dollar_at quotes CTLESC, even if quoted == 0 */ + ret = string_list_dollar_at (list, quoted, 0); +#else ret = string_list_dollar_star (list, quoted, 0); +#endif else ret = string_list ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) ? quote_list (list) : list); @@ -5777,7 +5787,7 @@ variable_remove_pattern (char *value, char *pattern, int patspec, int quoted) #endif static char * -list_remove_pattern (WORD_LIST *list, char *pattern, int patspec, int itype, int quoted) +list_remove_pattern (WORD_LIST *list, char *pattern, int patspec, int itype, int quoted, int pflags) { WORD_LIST *new, *l; WORD_DESC *w; @@ -5792,14 +5802,14 @@ list_remove_pattern (WORD_LIST *list, char *pattern, int patspec, int itype, int } l = REVERSE_LIST (new, WORD_LIST *); - tword = string_list_pos_params (itype, l, quoted, 0); + tword = string_list_pos_params (itype, l, quoted, pflags); dispose_words (l); return (tword); } static char * -parameter_list_remove_pattern (int itype, char *pattern, int patspec, int quoted) +parameter_list_remove_pattern (int itype, char *pattern, int patspec, int quoted, int pflags) { char *ret; WORD_LIST *list; @@ -5807,7 +5817,7 @@ parameter_list_remove_pattern (int itype, char *pattern, int patspec, int quoted list = list_rest_of_args (); if (list == 0) return ((char *)NULL); - ret = list_remove_pattern (list, pattern, patspec, itype, quoted); + ret = list_remove_pattern (list, pattern, patspec, itype, quoted, pflags); dispose_words (list); return (ret); } @@ -5815,7 +5825,7 @@ parameter_list_remove_pattern (int itype, char *pattern, int patspec, int quoted #if defined (ARRAY_VARS) /* STARSUB is so we can figure out how it's indexed */ static char * -array_remove_pattern (SHELL_VAR *var, char *pattern, int patspec, int starsub, int quoted) +array_remove_pattern (SHELL_VAR *var, char *pattern, int patspec, int starsub, int quoted, int pflags) { ARRAY *a; HASH_TABLE *h; @@ -5834,7 +5844,7 @@ array_remove_pattern (SHELL_VAR *var, char *pattern, int patspec, int starsub, i list = a ? array_to_word_list (a) : (h ? assoc_to_word_list (h) : 0); if (list == 0) return ((char *)NULL); - ret = list_remove_pattern (list, pattern, patspec, itype, quoted); + ret = list_remove_pattern (list, pattern, patspec, itype, quoted, pflags); dispose_words (list); return ret; @@ -5844,7 +5854,7 @@ array_remove_pattern (SHELL_VAR *var, char *pattern, int patspec, int starsub, i static char * parameter_brace_remove_pattern (char *varname, char *value, array_eltstate_t *estatep, char *patstr, - int rtype, int quoted, int flags) + int rtype, int quoted, int pflags, int flags) { int vtype, patspec, starsub; char *temp1, *val, *pattern, *oname; @@ -5894,7 +5904,7 @@ parameter_brace_remove_pattern (char *varname, char *value, break; #if defined (ARRAY_VARS) case VT_ARRAYVAR: - temp1 = array_remove_pattern (v, pattern, patspec, starsub, quoted); + temp1 = array_remove_pattern (v, pattern, patspec, starsub, quoted, pflags); if (temp1 && ((quoted & (Q_HERE_DOCUMENT|Q_DOUBLE_QUOTES)) == 0)) { val = quote_escapes (temp1); @@ -5904,7 +5914,7 @@ parameter_brace_remove_pattern (char *varname, char *value, break; #endif case VT_POSPARMS: - temp1 = parameter_list_remove_pattern (varname[0], pattern, patspec, quoted); + temp1 = parameter_list_remove_pattern (varname[0], pattern, patspec, quoted, pflags); if (temp1 && quoted == 0 && ifs_is_null) { /* Posix interp 888 */ @@ -8783,12 +8793,12 @@ array_var_assignment (SHELL_VAR *v, int itype, int quoted, int atype) #endif static char * -pos_params_assignment (WORD_LIST *list, int itype, int quoted) +pos_params_assignment (WORD_LIST *list, int itype, int quoted, int pflags) { char *temp, *ret; /* first, we transform the list to quote each word. */ - temp = list_transform ('Q', (SHELL_VAR *)0, list, itype, quoted); + temp = list_transform ('Q', (SHELL_VAR *)0, list, itype, quoted, 0); ret = (char *)xmalloc (strlen (temp) + 8); strcpy (ret, "set -- "); strcpy (ret + 7, temp); @@ -8848,7 +8858,7 @@ string_transform (int xc, SHELL_VAR *v, char *s) } static char * -list_transform (int xc, SHELL_VAR *v, WORD_LIST *list, int itype, int quoted) +list_transform (int xc, SHELL_VAR *v, WORD_LIST *list, int itype, int quoted, int pflags) { WORD_LIST *new, *l; WORD_DESC *w; @@ -8870,14 +8880,14 @@ list_transform (int xc, SHELL_VAR *v, WORD_LIST *list, int itype, int quoted) if (itype == '*' && expand_no_split_dollar_star && ifs_is_null) qflags |= Q_DOUBLE_QUOTES; /* Posix interp 888 */ - tword = string_list_pos_params (itype, l, qflags, 0); + tword = string_list_pos_params (itype, l, qflags, pflags); dispose_words (l); return (tword); } static char * -parameter_list_transform (int xc, int itype, int quoted) +parameter_list_transform (int xc, int itype, int quoted, int pflags) { char *ret; WORD_LIST *list; @@ -8886,9 +8896,9 @@ parameter_list_transform (int xc, int itype, int quoted) if (list == 0) return ((char *)NULL); if (xc == 'A') - ret = pos_params_assignment (list, itype, quoted); + ret = pos_params_assignment (list, itype, quoted, pflags); else - ret = list_transform (xc, (SHELL_VAR *)0, list, itype, quoted); + ret = list_transform (xc, (SHELL_VAR *)0, list, itype, quoted, pflags); dispose_words (list); return (ret); } @@ -8896,7 +8906,7 @@ parameter_list_transform (int xc, int itype, int quoted) #if defined (ARRAY_VARS) /* STARSUB so we can figure out how it's indexed */ static char * -array_transform (int xc, SHELL_VAR *var, int starsub, int quoted) +array_transform (int xc, SHELL_VAR *var, int starsub, int quoted, int pflags) { ARRAY *a; HASH_TABLE *h; @@ -8939,7 +8949,7 @@ array_transform (int xc, SHELL_VAR *var, int starsub, int quoted) if (itype == '*' && expand_no_split_dollar_star && ifs_is_null) qflags |= Q_DOUBLE_QUOTES; /* Posix interp 888 */ - ret = string_list_pos_params (itype, list, qflags, 0); + ret = string_list_pos_params (itype, list, qflags, pflags); dispose_words (list); return ret; } @@ -8947,7 +8957,7 @@ array_transform (int xc, SHELL_VAR *var, int starsub, int quoted) list = a ? array_to_word_list (a) : (h ? assoc_to_word_list (h) : 0); if (list == 0) return ((char *)NULL); - ret = list_transform (xc, v, list, itype, quoted); + ret = list_transform (xc, v, list, itype, quoted, pflags); dispose_words (list); return ret; @@ -9035,7 +9045,7 @@ parameter_brace_transform (char *varname, char *value, array_eltstate_t *estatep break; #if defined (ARRAY_VARS) case VT_ARRAYVAR: - temp1 = array_transform (xc, v, starsub, quoted); + temp1 = array_transform (xc, v, starsub, quoted, pflags); if (temp1 && quoted == 0 && ifs_is_null) { /* Posix interp 888 */ @@ -9049,7 +9059,7 @@ parameter_brace_transform (char *varname, char *value, array_eltstate_t *estatep break; #endif case VT_POSPARMS: - temp1 = parameter_list_transform (xc, varname[0], quoted); + temp1 = parameter_list_transform (xc, varname[0], quoted, pflags); if (temp1 && quoted == 0 && ifs_is_null) { /* Posix interp 888 */ @@ -10391,7 +10401,7 @@ bad_substitution: FREE (value); break; } - temp1 = parameter_brace_remove_pattern (name, temp, &es, value, c, quoted, (tflag & W_ARRAYIND) ? AV_USEIND : 0); + temp1 = parameter_brace_remove_pattern (name, temp, &es, value, c, quoted, pflags, (tflag & W_ARRAYIND) ? AV_USEIND : 0); free (temp); free (value); #if defined (ARRAY_VARS) diff --git a/tests/RUN-ONE-TEST b/tests/RUN-ONE-TEST index f3a23b8f..74e58890 100755 --- a/tests/RUN-ONE-TEST +++ b/tests/RUN-ONE-TEST @@ -12,7 +12,8 @@ rm -f ${BASH_TSTOUT} if [ -t 1 ]; then if type -P tput >/dev/null; then - CSTART=$(tput setaf 15 setab 1) CEND=$(tput sgr0) +# CSTART=$(tput setaf 15 setab 1) CEND=$(tput sgr0) + CSTART=$(tput bold ; tput setab 9 ; tput setaf 7) CEND=$(tput sgr0) else # can't rely on having $'...' or printf understanding \e # bright red background, white foreground text diff --git a/tests/RUN-TEST-SCRIPT b/tests/RUN-TEST-SCRIPT index fec43b2d..814cfbc1 100755 --- a/tests/RUN-TEST-SCRIPT +++ b/tests/RUN-TEST-SCRIPT @@ -12,7 +12,8 @@ rm -f ${BASH_TSTOUT} if [ -t 1 ]; then if type -P tput >/dev/null; then - CSTART=$(tput setaf 15 setab 1) CEND=$(tput sgr0) +# CSTART=$(tput setaf 15 setab 1) CEND=$(tput sgr0) + CSTART=$(tput bold ; tput setab 9 ; tput setaf 7) CEND=$(tput sgr0) else # can't rely on having $'...' or printf understanding \e # bright red background, white foreground text diff --git a/tests/builtins.right b/tests/builtins.right index 740dc47f..d7fcd38f 100644 --- a/tests/builtins.right +++ b/tests/builtins.right @@ -354,7 +354,7 @@ found ./builtins9.sub: line 52: hash: /: Is a directory builtin hash -p /nosuchfile cat builtins10.sub -./builtins10.sub: line 17: help: -x: invalid option +./builtins10.sub: line 19: help: -x: invalid option help: usage: help [-dms] [pattern ...] These shell commands are defined internally. Type `help' to see this list. Type `help name' to find out more about the function `name'. @@ -495,7 +495,9 @@ A star (*) next to a name means that the command is disabled. getopts optstring name [arg ...] while COMMANDS; do COMMANDS-2; done hash [-lr] [-p pathname] [-dt] [name > { COMMANDS ; } help [-dms] [pattern ...] -./builtins10.sub: line 39: help: no help topics match 'bash'. Try 'help help', 'man -k bash', or 'info bash'. +./builtins10.sub: line 41: help: no help topics match 'bash'. Try 'help help', 'man -k bash', or 'info bash'. +Shell commands matching pattern 'ad*x': +./builtins10.sub: line 44: help: no help topics match 'ad*x'. builtins11.sub unlimited unlimited diff --git a/tests/builtins10.sub b/tests/builtins10.sub index e8413f81..32607965 100644 --- a/tests/builtins10.sub +++ b/tests/builtins10.sub @@ -13,6 +13,8 @@ # # have to run through sed or grep to filter out version information +COLUMNS=80 + # let's exercise print-help help -x @@ -37,3 +39,6 @@ help -- | sed 1d # maybe sometime in the future this will do something help -- bash + +# Tinkering with format for pattern output +help 'ad*x' diff --git a/tests/exp.right b/tests/exp.right index ac4e014a..739e68d0 100644 --- a/tests/exp.right +++ b/tests/exp.right @@ -446,3 +446,31 @@ declare -i a="7" declare -- a="42" FOO declare -u A="FOO" + exp14.sub +!Q= + Q= +!Q= +Q= +!Q- + Q- +!Q? + Q? +!Q+ + Q+ ++Q+ +!Q: +Q: +!Q# +Q# +!Q% +Q% +!Q/ +Q/ +!Q^ +Q^ +!Q, +Q, +!Q@Q <'a' 'b' 'c'> <'a':'b':'c'> +Q@Q <'a':'b':'c'> <'a':'b':'c'> +!Q@A +Q@A diff --git a/tests/exp.tests b/tests/exp.tests index ca752fdc..f61b6eb2 100644 --- a/tests/exp.tests +++ b/tests/exp.tests @@ -430,3 +430,4 @@ test_runsub ./exp10.sub test_runsub ./exp11.sub test_runsub ./exp12.sub test_runsub ./exp13.sub +test_runsub ./exp14.sub diff --git a/tests/exp14.sub b/tests/exp14.sub new file mode 100644 index 00000000..bfe4b29e --- /dev/null +++ b/tests/exp14.sub @@ -0,0 +1,69 @@ +# 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 . +# +# +# tests for quoted and unquoted expansions of $@/$* in contexts without +# word splitting + +set -- a b c +OIFS="$IFS" + +IFS=:; o=$@ s=$*; printf '!Q= <%s> <%s>\n' "$o" "$s" ; IFS=$OIFS +IFS=:; o="$@" s="$*"; printf ' Q= <%s> <%s>\n' "$o" "$s" ; IFS=$OIFS +IFS=:; o=${@} s=${*}; printf '!Q= <%s> <%s>\n' "$o" "$s" ; IFS=$OIFS +IFS=:; o="${@}" s="${*}"; printf 'Q= <%s> <%s>\n' "$o" "$s" ; IFS=$OIFS +IFS=:; o=${@-x} s=${*-x}; printf '!Q- <%s> <%s>\n' "$o" "$s" ; IFS=$OIFS +IFS=:; o="${@-x}" s="${*-x}"; printf ' Q- <%s> <%s>\n' "$o" "$s" ; IFS=$OIFS +IFS=:; o=${@?x} s=${*?x}; printf '!Q? <%s> <%s>\n' "$o" "$s" ; IFS=$OIFS +IFS=:; o="${@?x}" s="${*?x}"; printf ' Q? <%s> <%s>\n' "$o" "$s" ; IFS=$OIFS +IFS=:; o=${@+$@} s=${*+$*}; printf '!Q+ <%s> <%s>\n' "$o" "$s" ; IFS=$OIFS +IFS=:; o="${@+$@}" s="${*+$*}"; printf ' Q+ <%s> <%s>\n' "$o" "$s" ; IFS=$OIFS +IFS=:; o=${@+"$@"} s=${*+"$*"}; printf '+Q+ <%s> <%s>\n' "$o" "$s" ; IFS=$OIFS + +# positional parameter substring expansion +IFS=:; o=${@:1} s=${*:1}; printf '!Q: <%s> <%s>\n' "$o" "$s" ; IFS=$OIFS +IFS=:; o="${@:1}" s="${*:1}"; printf 'Q: <%s> <%s>\n' "$o" "$s" ; IFS=$OIFS + +set -- aa bb cc + +# positional parameter pattern removal +IFS=:; o=${@#?} s=${*#?}; printf '!Q# <%s> <%s>\n' "$o" "$s" ; IFS=$OIFS +IFS=:; o="${@#?}" s="${*#?}"; printf 'Q# <%s> <%s>\n' "$o" "$s" ; IFS=$OIFS + +IFS=:; o=${@%?} s=${*%?}; printf '!Q%% <%s> <%s>\n' "$o" "$s" ; IFS=$OIFS +IFS=:; o="${@%?}" s="${*%?}"; printf 'Q%% <%s> <%s>\n' "$o" "$s" ; IFS=$OIFS + +set -- a b c + +# positional parameter pattern substitution +IFS=:; o=${@/?/x} s=${*/?/x}; printf '!Q/ <%s> <%s>\n' "$o" "$s" ; IFS=$OIFS +IFS=:; o="${@/?/x}" s="${*/?/x}"; printf 'Q/ <%s> <%s>\n' "$o" "$s" ; IFS=$OIFS + +# positional parameter case modification +IFS=:; o=${@^[abc]} s=${*^[abc]}; printf '!Q^ <%s> <%s>\n' "$o" "$s" ; IFS=$OIFS +IFS=:; o="${@^[abc]}" s="${*^[abc]}"; printf 'Q^ <%s> <%s>\n' "$o" "$s" ; IFS=$OIFS + +set -- A B C + +IFS=:; o=${@,[ABC]} s=${*,[ABC]}; printf '!Q, <%s> <%s>\n' "$o" "$s" ; IFS=$OIFS +IFS=:; o="${@,[ABC]}" s="${*,[ABC]}"; printf 'Q, <%s> <%s>\n' "$o" "$s" ; IFS=$OIFS + +set -- a b c + +# positional parameter transformation -- quoting +IFS=:; o=${@@Q} s=${*@Q}; printf '!Q@Q <%s> <%s>\n' "$o" "$s" ; IFS=$OIFS +IFS=:; o="${@@Q}" s="${*@Q}"; printf 'Q@Q <%s> <%s>\n' "$o" "$s" ; IFS=$OIFS + +# positional parameter transformation -- assignment +IFS=:; o=${@@A} s=${*@A}; printf '!Q@A <%s> <%s>\n' "$o" "$s" ; IFS=$OIFS +IFS=:; o="${@@A}" s="${*@A}"; printf 'Q@A <%s> <%s>\n' "$o" "$s" ; IFS=$OIFS diff --git a/tests/run-all b/tests/run-all index cf795478..762d662d 100644 --- a/tests/run-all +++ b/tests/run-all @@ -63,7 +63,8 @@ echo Any output from any test, unless otherwise noted, indicates a possible anom # keep track of passed and failed tests and report them if [ -t 1 ]; then if type -P tput >/dev/null; then - CSTART=$(tput setaf 15 setab 1) CEND=$(tput sgr0) +# CSTART=$(tput bold ; tput setaf 15 ; tput setab 1) CEND=$(tput sgr0) + CSTART=$(tput bold ; tput setab 9 ; tput setaf 7) CEND=$(tput sgr0) else # can't rely on having $'...' or printf understanding \e # bright red background, white foreground text diff --git a/variables.c b/variables.c index 6a03175e..00a73da8 100644 --- a/variables.c +++ b/variables.c @@ -820,11 +820,24 @@ get_bash_name (void) tname = make_absolute (shell_name, get_string_value ("PWD")); if (*shell_name == '.') { + char *x, *fp; + + x = strrchr (tname, '/'); + *x = 0; name = sh_canonpath (tname, PATH_CHECKDOTDOT|PATH_CHECKEXISTS); + *x++ = '/'; if (name == 0) name = tname; else - free (tname); + { + fp = sh_makepath (name, x, 0); + free (tname); + if (fp) + { + free (name); + name = fp; + } + } } else name = tname;