Bash crashes if you try to mapfile into an associative array
From: Nick Hobson To: bug-bash@gnu.org Subject: Bash crashes if you try to mapfile into an associative array Configuration Information [Automatically generated, do not change]: Machine: i686 OS: linux-gnu Compiler: gcc Compilation CFLAGS: -DPROGRAM='bash' -DCONF_HOSTTYPE='i686' -DCONF_OSTYPE='linux-gnu' -DCONF_MACHTYPE='i686-pc-linux-gnu' -DCONF_VENDOR='pc' -DLOCALEDIR='/usr/share/locale' -DPACKAGE='bash' -DSHELL -DHAVE_CONFIG_H -I. -I. -I./include -I./lib -march=i686 -mtune=generic -O2 -pipe uname output: Linux localhost 2.6.31-ARCH #1 SMP PREEMPT Tue Oct 13 13:36:23 CEST 2009 i686 Intel(R) Celeron(R) CPU 550 @ 2.00GHz GenuineIntel GNU/Linux Machine Type: i686-pc-linux-gnu Bash Version: 4.0 Patch Level: 33 Release Status: release Description: If you declare an array to be associative and then try to mapfile (or readarray) into it, Bash crashes. Repeat-By: declare -A x mapfile x
IFS=: breaks literal patterns with character classes
Configuration Information [Automatically generated, do not change]: Machine: i386 OS: linux-gnu Compiler: gcc Compilation CFLAGS: -DPROGRAM='bash' -DCONF_HOSTTYPE='i386' -DCONF_OSTYPE='linux-gnu' -DCONF_MACHTYPE='i386-redhat-linux-gnu' -DCONF_VENDOR='redhat' -DLOCALE DIR='/usr/share/locale' -DPACKAGE='bash' -DSHELL -DHAVE_CONFIG_H -I. -I. -I./include -I./lib -D_GNU_SOURCE -D_LARGEFILE_SOURCE -D_FILE_OFFSET_BITS=64 -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -fexceptions -fstack-protector --param=ssp-buffer-size=4 -m32 -march=i586 -mtune=generic -fasynchronous-unwind-tables uname output: Linux apeiron.home.lan 2.6.29.4-167.fc11.i586 #1 SMP Wed May 27 17:14:37 EDT 2009 i686 i686 i386 GNU/Linux Machine Type: i386-redhat-linux-gnu Bash Version: 4.0 Patch Level: 23 Release Status: release Description: See the Repeat-by section. Character class [:graph:] appears not to match as it should, if IFS=':'. Why, or at what stage, is IFS used here? Repeat-By: $ # Correct: $ (IFS=' '; case A in ([[:graph:]]) echo graph;; (*) echo non-graph;; esac) graph $ # Not correct: $ (IFS=':'; case A in ([[:graph:]]) echo graph;; (*) echo non-graph;; esac) non-graph $ # Contrast with $ (IFS=:; echo a:b) a:b $ # The error also happens with the == operator: $ # Correct: $ (IFS=' '; [[ A == [[:graph:]] ]] && echo yes || echo no) yes $ # Not correct $ (IFS=':'; [[ A == [[:graph:]] ]] && echo yes || echo no) no
PS1 prompt problem
I'm using bash 3.2 and I'd like to set my prompt to the following (inspired by the Opensolaris prompt for ksh93): PS1='$( spwd="${PWD/#${HOME}/~}" [[ ${#spwd} -gt 10 ]] && spwd="...${spwd: -10}" printf "%...@%s:%s%s " "\u" "\h" "${spwd}" "\$" termtitle="\...@\h:${spwd}" printf "%s" "\[" case "${TERM}" in (xterm*) printf "\033]0;%s\a" "${termtitle}" ;; (screen*) printf "\033_%s\033\\" "${termtitle}" ;; esac printf "%s" "\]" )' Basically this is supposed to shorten PWD to the last 10 characters and set the terminal title as well. Unfortunately it causes bash to hang, the problem seems to lie in the escape codes for entering and leaving the terminal title and the surrounding "\[" "\]" because commenting out the case statement and the surrounding printfs makes it at least set the prompt correctly. I have the strong suspicion it might be some quoting issue. Using printf "\033]0;%s\a" "${PWD}" on the command line will set the xterm title to $PWD. Setting PROMPT_COMMAND='printf "\033]0;%s\a" "${PWD}"' works as well, however I do not want to use $PROMPT_COMMAND for efficiency reasons as I would have to calculate $spwd (and possibly other things later) twice. Following a suggestion in comp.unix.shell putting the above code contained in $() inside a separate function f and setting PS1='$( f )' displays the $spwd correctly in both the prompt and xterm title, but bash escapes like "\u", "\h" etc are not expanded any more What's wrong here?
Re: Bash crashes if you try to mapfile into an associative array
Nick Hobson wrote: > From: Nick Hobson > To: bug-bash@gnu.org > Subject: Bash crashes if you try to mapfile into an associative array > > Configuration Information [Automatically generated, do not change]: > Machine: i686 > OS: linux-gnu > Compiler: gcc > Compilation CFLAGS: -DPROGRAM='bash' -DCONF_HOSTTYPE='i686' > -DCONF_OSTYPE='linux-gnu' -DCONF_MACHTYPE='i686-pc-linux-gnu' > -DCONF_VENDOR='pc' -DLOCALEDIR='/usr/share/locale' -DPACKAGE='bash' -DSHELL > -DHAVE_CONFIG_H -I. -I. -I./include -I./lib -march=i686 -mtune=generic > -O2 -pipe > uname output: Linux localhost 2.6.31-ARCH #1 SMP PREEMPT Tue Oct 13 13:36:23 > CEST 2009 i686 Intel(R) Celeron(R) CPU 550 @ 2.00GHz GenuineIntel GNU/Linux > Machine Type: i686-pc-linux-gnu > > Bash Version: 4.0 > Patch Level: 33 > Release Status: release > > Description: > If you declare an array to be associative and then try to mapfile (or > readarray) into it, Bash crashes. > That's an incorrect use of `mapfile' -- mapfile takes an indexed array -- but the shell still shouldn't crash by assuming the variable is an indexed array. I'll fix that for bash-4.1. Chet -- ``The lyf so short, the craft so long to lerne.'' - Chaucer ``Ars longa, vita brevis'' - Hippocrates Chet Ramey, ITS, CWRUc...@case.eduhttp://cnswww.cns.cwru.edu/~chet/
Re: PS1 prompt problem
Nils writes: > Following a suggestion in comp.unix.shell putting the above code > contained in $() inside a separate function f and setting PS1='$( f )' > displays the $spwd correctly in both the prompt and xterm title, but > bash escapes like "\u", "\h" etc are not expanded any more You could pass them as arguments to the function. > What's wrong here? You are faced with multi-level expansion and need to protect the special characters that you want to be preserved for the later levels. Before the command substitution is expanded all backslash sequences are expanded, so for example "\033_%s\033\\" becomes "^[_%s^[\" (where ^[ denotes the literal escape character). The trailing backslash is now quoting the quote character, which results in an unmatched quote. Thus you should write "\\033_%s\\033" instead. PS1='$( spwd="${PWD/#${HOME}/~}" [[ ${#spwd} -gt 10 ]] && spwd="...${spwd: -10}" printf "%...@%s:%s%s " "\u" "\h" "${spwd}" "\$" termtitle="\...@\h:${spwd}" printf "%s" "\[" case "${TERM}" in (xterm*) printf "\\033]0;%s\\a" "${termtitle}" ;; (screen*) printf "\\033_%s\\033" "${termtitle}" ;; esac printf "%s" "\]" )' Andreas. -- Andreas Schwab, sch...@linux-m68k.org GPG Key fingerprint = 58CA 54C7 6D53 942B 1756 01D3 44D5 214B 8276 4ED5 "And now for something completely different."
Re: PS1 prompt problem
Nils wrote: > I'm using bash 3.2 and I'd like to set my prompt to the following > (inspired by the Opensolaris prompt for ksh93): > > PS1='$( > spwd="${PWD/#${HOME}/~}" > [[ ${#spwd} -gt 10 ]] && spwd="...${spwd: -10}" > printf "%...@%s:%s%s " "\u" "\h" "${spwd}" "\$" > termtitle="\...@\h:${spwd}" > > > printf "%s" "\[" > case "${TERM}" in > (xterm*) > printf "\033]0;%s\a" "${termtitle}" > ;; > (screen*) > printf "\033_%s\033\\" "${termtitle}" > ;; > esac > printf "%s" "\]" > > )' > > Basically this is supposed to shorten PWD to the last 10 characters > and set the terminal title as well. Unfortunately it causes bash to > hang, the problem seems to lie in the escape codes for entering and > leaving the terminal title and the surrounding "\[" "\]" because > commenting out the case statement and the surrounding printfs makes it > at least set the prompt correctly. I have the strong suspicion it > might be some quoting issue. Sort of. I think you're overlooking the various expansion (and backslash escaping) that's taking place with your prompt. Since you set the value of PS1 to literal string containing a command substitution, the value will be expanded twice before being sent to readline. The first expansion is the normal set of backslash escapes performed by prompt string decoding; the second is the set of shell word expansions, including command substitution. This is the problem line: printf "\033_%s\033\\" "${termtitle}". I assume the intent is to wind up with a string ending with a single backslash written to the terminal. The string as written results in a parsing error. One of the prompt string decoding expansions turns \\ into \, so the form of the above string when passed to the parser by the command substitution is printf "ESC_%sESC\" "${termtitle}" (the ESC stands for a literal escape character). The escaped double quote is probably not what's intended. For printf to see what you want it to, you need to double the backslashes in that string: printf "\033_%s\033" "${termtitle}" Try that and see what you get. Chet -- ``The lyf so short, the craft so long to lerne.'' - Chaucer ``Ars longa, vita brevis'' - Hippocrates Chet Ramey, ITS, CWRUc...@case.eduhttp://cnswww.cns.cwru.edu/~chet/
Re: PS1 prompt problem
On 16 Okt., 21:18, Chet Ramey wrote: > Sort of. I think you're overlooking the various expansion (and backslash > escaping) that's taking place with your prompt. > > Since you set the value of PS1 to literal string containing a command > substitution, the value will be expanded twice before being sent to > readline. The first expansion is the normal set of backslash escapes > performed by prompt string decoding; the second is the set of shell word > expansions, including command substitution. > > This is the problem line: printf "\033_%s\033\\" "${termtitle}". I > assume the intent is to wind up with a string ending with a single > backslash written to the terminal. The string as written results in > a parsing error. > > One of the prompt string decoding expansions turns \\ into \, so the > form of the above string when passed to the parser by the command > substitution is > > printf "ESC_%sESC\" "${termtitle}" > > (the ESC stands for a literal escape character). The escaped double quote > is probably not what's intended. > > For printf to see what you want it to, you need to double the backslashes > in that string: > > printf "\033_%s\033" "${termtitle}" > > Try that and see what you get. Yes, that was the problem, I did not take into account that bash expands $PS1 twice. This is easy to reproduce by setting PS1='$ ( printf "\\" )' which works with ash, ksh93, ksh88 but fails with bash which needs PS1='$( printf "" )'. Is this double expansion even POSIX compliant? The spec says that "[e]ach time an interactive shell is ready to read a command, the value of this variable shall be subjected to parameter expansion..." (http://www.opengroup.org/ onlinepubs/009695399/utilities/xcu_chap02.html#tag_02_05_03)
Re: PS1 prompt problem
Nils wrote: > > Yes, that was the problem, I did not take into account that bash > expands $PS1 twice. No, it doesn't. It performs additional expansions besides those specified by Posix. > Is this double expansion even POSIX compliant? Yes. -- ``The lyf so short, the craft so long to lerne.'' - Chaucer ``Ars longa, vita brevis'' - Hippocrates Chet Ramey, ITS, CWRUc...@case.eduhttp://cnswww.cns.cwru.edu/~chet/
Re: IFS=: breaks literal patterns with character classes
Enrique Perez-Terron wrote: > Bash Version: 4.0 > Patch Level: 23 > Release Status: release > > Description: > See the Repeat-by section. Character class [:graph:] appears not to > match as it > should, if IFS=':'. Why, or at what stage, is IFS used here? Thanks for the report. This will be fixed in bash-4.1. Chet -- ``The lyf so short, the craft so long to lerne.'' - Chaucer ``Ars longa, vita brevis'' - Hippocrates Chet Ramey, ITS, CWRUc...@case.eduhttp://cnswww.cns.cwru.edu/~chet/
Re: Oddities when tab-completing filenames containing backticks
bash-b...@atu.cjb.net wrote: > Bash Version: 4.0 > Patch Level: 39 > Release Status: release > > Description: > >Also affects Bash 4.0.33. > >When a filename begins with a backtick ` then tab-completion works >as expected if you go \`, however if you try to tab-complete >the filename inside single quotes, several strange behaviours appear. You need to remember that readline understands the characters in rl_completer_quote_characters as those which, in pairs, delimit quoted substrings in the line. It performs completion (allowing the application to take first crack, of course) on the substring, using the text after the open quote. The other thing to keep in mind is that readline doesn't look past point when performing completion -- it only considers characters from the beginning of the line or a quote character up to point. My answers below are for the built-in bash completion, not any programmable completions you might have defined. > Repeat-By: > >1) '` This causes all commands available on the system to be >listed such as `awk `bash etc., even though it's inside >single quotes. Readline does completion on substrings; it passes ` to the bash completion code, which performs command completion. > >2) '`text This completes the filename, but it does not insert a >trailing single quote as tab-completion would usually do. Bash receives "`text", does command completion on `text' and suppresses the append of the close quote, since it's usually wrong in this case. >3) '`dir This completes the directory name and adds the trailing >forward slash, but not the trailing single quote. Again, appending the trailing single quote without the trailing ` is generally going to be wrong. >4) 'text` This completes the filename and closes the single quote >as expected. Interesting. I don't get this behavior. >5) '`text' When using tab-completion inside single quotes on a >filename beginning with a backtick, then it completes >the filename and adds an additional closing single quote, >e.g. '`filename.txt'' Also interesting. I get normal command completion without any closing quote appended. >6) '`dir' When using tab-completion inside single quotes on a >directory name beginning with a backtick, then it >completes the directory name and adds an additional >closing single quote after the directory name and before >the forward slash, e.g. '`directory'/' I don't see this behavior either. Chet -- ``The lyf so short, the craft so long to lerne.'' - Chaucer ``Ars longa, vita brevis'' - Hippocrates Chet Ramey, ITS, CWRUc...@case.eduhttp://cnswww.cns.cwru.edu/~chet/