The idea of my PS1 configuration is to show some extended info like Mercurial or Git repo status, command execution time, etc. The prompt is split by two lines because it produces too many characters to fit into a single line. Here is my PS1 in my .bashrc (not sure if the entire source code is necessary here):

function prompt_status {
        local color_app="\e[1;38;5;214m"
        local color_branch="\e[1;38;5;32m"
        local color_revision="\e[0;38;5;64m"
        if git rev-parse --is-inside-work-tree &> /dev/null; then
                local branch="$(git rev-parse --abbrev-ref HEAD | tr -d '\n')"
                local revision="$(git rev-parse HEAD | tr -d '\n')"
                echo -ne $color_app"git "$color_branch"$branch "$color_revision"($revision)"
        elif hg status &> /dev/null; then
                local branch="$(hg branch | tr -d '\n')"
                local revision_number="$(hg identify -n | tr -d '\n')"
                local revision="$(hg parent --template '{node}' | tr -d '\n')"
                echo -ne $color_app"hg "$color_branch"$branch "$color_revision"($revision_number:$revision)"
        echo -e " \e[0m"

function prompt_return_value {
        if [[ $RET -eq 0 ]]; then
                echo -ne "" #echo -ne "\e[32m$RET\e[0m"
                echo -ne "\e[1;37;41m$RET\e[0m "

function timer_start {

function timer_stop {
        seconds_elapsed=$(($SECONDS - $timer))
        unset timer

function prompt_seconds_elapsed {
        local c;
        local t=${seconds_elapsed}s
        if [ $seconds_elapsed -ge 60 ]; then
                t=$(format_seconds $seconds_elapsed)
        elif [ $seconds_elapsed -ge 20 ]; then
        elif [ $seconds_elapsed -ge 10 ]; then
        elif [ $seconds_elapsed -ge 5 ]; then
        elif [ $seconds_elapsed -ge 1 ]; then
        echo -ne "\e[0;38;5;${c}m${t} \e[0m"

function format_seconds {
        printf "%02d:%02d:%02d\n" $h $m $s

trap 'timer_start' DEBUG

export PS1="\n\e[1;38;5;106m\u@\h \e[0;38;5;136m\w\[\e[0m\]\n\$(prompt_return_value)\$(prompt_seconds_elapsed)\$(prompt_status)\$ "

The problem is that the prompt looks broken when a terminal window has small width. This is what I get for 80 columns:

username@some-very-long-hostname ~/tmp/d
06a14b06cac) $ 9866c9d0d26d2b27063a89ee1c330

It's like wrapped at the 2nd line causing total mess (see the $ sign in the middle). It works almost perfectly for a larger terminal column number, say 120:

username@some-very-long-hostname ~/tmp/d
hg default (0:69866c9d0d26d2b27063a89ee1c3306a14b06cac) $

Also I noticed that add more text to the end of the terminal line causes an issue that's very similar to the effects described for 80 columns above. The question is: does bash handle new lines or "too long" incorrectly for PS1?



This question is not an exact duplicate of Why is my bash prompt getting bugged when I browse the history? . After some discussion with @AdamKatz, it seems that zero-length output escapes \[ and '] work only when they are literally put in the PS1 string, but they does not seem to work when returned from a function causing to appear unescaped on terminal.


1 Answer 1


For multi-line prompts (including when it wraps, including from your commands), you need to enclose your color codes in escaped square brackets (like \[$color\]).

This example is green, has user@hostname:workingdir $ and then reverts back to uncolored:

PS1='\[\e[1;32m\]\u@\h:\w \$\[\e[0;0m\]'

If you're seeing literal \[ or [ appear in your prompt, it's probably being expanded from \[ to [ before being interpreted for prompt expansion. In that case, try \001 for \[ and \002 for \] and you should be good to go. If you're not having luck with \e, try \033 instead. These octal codes are more portable since they'll pass through (programs like sed won't try to unescape or interpret them).

  • See also my $PS1 coloration and truncations among other colorizing techniques. (\033 is the same as \e but sometimes works better.)
    – Adam Katz
    Commented Mar 18, 2015 at 15:41
  • Thank you for the answer. It seems to work only when the color codes are specified in the string literal passed to PS1 like in your example demonstrates. However, when I add enclosing brackets to a function like prompt_return_value (see the question), then I get \[ and \] (example: \[128\], but 128 is still red) to appear in my prompt. It looks like the enclosing brackets only work when passed "directly" in the string. Can't make it work with my functions. Commented Mar 18, 2015 at 16:02
  • maybe try the escaped brackets in the final $PS1 assignment, even if the content between them is a variable, like \[$color\] as noted in my answer.
    – Adam Katz
    Commented Mar 18, 2015 at 16:09
  • As far as I understand, \[ and \] work as if they consume the terminal output causing the output to be interpreted as zero-length output. Have no idea how to escape the function output properly. Commented Mar 19, 2015 at 8:27
  • My ~/.bashrc contains this: PSC() { echo -ne "\[\e[${1:-0;0}m\]"; } and then the assignment contains things like PS1="$(PSC '1;32')\u…"
    – Adam Katz
    Commented Mar 19, 2015 at 14:40

Not the answer you're looking for? Browse other questions tagged .