Take the 2-minute tour ×
Unix & Linux Stack Exchange is a question and answer site for users of Linux, FreeBSD and other Un*x-like operating systems.. It's 100% free, no registration required.

I'm trying to set up a bash prompt for - hostname(screen#):directory$ which is coloured green if the last command completed successfully, red if not. This is what I have so far, which actually does the job but seems to cause display problems if the command wraps a line:

 PS1="\[\`if [[ \$? = "0" ]]; then echo '\e[32m'; else echo '\e[31m' ; fi\` - \h(${WINDOW}):\W$\e[00m "

Googling the issue I found this helpful SO post with a comment that mentions wrapping nonprinting characters in \\[ and \\] to avoid this issue. Therefore I tried the following, but it did not solve the issue, and furthermore breaks the colour change:

PS1="\[\`if [[ \$? = "0" ]]; then echo '\e[32m'; else echo '\e[31m' ; fi\`\] - \h(${WINDOW}):\W$\[\e[00m\] "

How can I keep the structure of this prompt, with colours, but fix it so that long commands are displayed properly?

share|improve this question

4 Answers 4

up vote 10 down vote accepted

I have a fancy prompt with colors, and now bash doesn't seem to know how wide my terminal is. Lines wrap around incorrectly.


I have another proper way to do this, put this code in your ~/.bashrc or create a new file and source file :

PROMPT_COMMAND=$(
    cat<<-'EOF'

    retval=$?

    RED=$(tput setaf 1)
    GREEN=$(tput setaf 2)
    STOP=$(tput sgr0)

    # arithmetic using bash parameter expansion on a array
    if (($retval + ${PIPESTATUS[@]/%/+} + 0)); then
        PS1="\[$RED\]\u@\h:\w$ \[$STOP\]"
    else
        PS1="\[$GREEN\]\u@\h:\w$ \[$STOP\]"
    fi
EOF
)

That will do the trick =)

Bash will run the code inside PROMPT_COMMAND for each commands.

If you have copy/paste problem, you can download the script

tput

EXPLANATIONS

  • (( )) is arithmetic in bash, see http://wiki.bash-hackers.org/syntax/arith_expr
  • PROMPT_COMMAND : if set, the value is executed as a command prior to issuing each primary prompt. See man bash | less +/PROMPT_COMMAND
  • tput is better than hard coding ANSI escape codes. See http://wiki.bash-hackers.org/scripting/terminalcodes
  • PIPESTATUS : An array variable containing a list of exit status values from the processes in the most-recently-executed foreground pipeline (which may contain only a single command). See man bash | less +/PIPESTATUS
  • cat<<-'EOF' is a special here doc : the - character means I can indent code, and the single quotes on 'EOF' means to not interpolate variables
share|improve this answer
    
Added doc link about your problem –  StardustOne Nov 20 '12 at 21:15
    
Thanks. I am getting an unexpected EOF while looking for matching `)' on the line that defines the function. Near as I can tell it seems that bash thinks that there is an unclosed ( in the do line, but I really don't see how that could be. –  dotancohen Nov 20 '12 at 22:07
    
This is a copy & paste problem, this will disappear if you reindent. –  StardustOne Nov 20 '12 at 22:16
    
Actually, I did reindent, with tabs. Everything inside the function got one tab save for the lines that begin PS1, which got two tabs. –  dotancohen Nov 20 '12 at 22:26
1  
Thank you Sputnik! I learned a lot from this post, not only about the prompt but about other aspects as well. You were very helpful and I've found some goodies in you back posts as well that I'm going through to learn from. Thanks! –  dotancohen Nov 20 '12 at 22:46

Not \\[, just \[. You also have an extra \[ at the start.

share|improve this answer
    
Thanks, I updated the question. In fact, I had already taken care of the `\\` issue before I posted. –  dotancohen Nov 20 '12 at 19:12

I have a 2-line prompt, so the potentially long stuff won't affect the command line:

glennj@homebase ~/tmp
2219 $ set | grep PS1=
PS1='\n\u@\h \w\n\! \$ '
share|improve this answer

This is not a direct answer to the original question, it is just a usage example.

Based and thanks to @stArdustͲ's answer, I found a proper solution for a custom command prompt to show up the battery's status*, on the top right corner of the terminal. The colors are defined in an independent file which is sourced from inside .bashrc.

PROMPT_COMMAND=$(
    cat<<-'EOF'
    function battery_percentage {
        PERCENTAGE=$(upower -i $(echo $(upower -e |grep 'battery')) |grep 'percentage' |sed -e 's/^[ \t]*//;s/[[:space:]]\+/ /g;s/[ \t]*$//' |cut -d' ' -f2 |cut -d"%" -f1)
        BColor='IGray'
        if [ "${PERCENTAGE}" -lt 15 ]
            then PColor='BlinkIRed'
                 PBackground='On_White'
            else PColor='Gray'
        fi
        echo "\001${!BColor}\002Battery\001${!PColor}\002 ${PERCENTAGE}% \001${Reset}\002"
    }

    function battery_time {
        TIME=$(upower -i $(echo $(upower -e |grep 'battery')) |grep 'time' |sed -e 's/^[ \t]*//;s/[[:space:]]\+/ /g;s/[ \t]*$//' |cut -d' ' -f4,5)
        echo "\001${IGray}\002${TIME}\001${Reset}\002"
    }

    export PS1="\[\e[s\]\[\e[1;\$((COLUMNS-26))f\]$(battery_percentage) $(battery_time)\[\e[u\]${PS1}"
EOF
)

Finally, the PS1 looks like:

\[\e[s\]\[\e[1;$((COLUMNS-26))f\]\001\e[0;38;5;8m\002Battery\001\e[0;38;5;7m\002 82% \001\e[0m\002 \001\e[0;38;5;8m\0023.6 hours\001\e[0m\002\[\e[u\]\[\e[0;38;5;232m\]\[\e[48;5;5m\] \u \[\e[0;38;5;5m\]\[\e[48;5;11m\] \[\e[0;38;5;232m\]\[\e[48;5;11m\]@\H \[\e[0;38;5;11m\]\[\e[48;5;0m\]\[\e[0m\] \[\e[0;38;5;6m\]\w\a \[\e[1;38;5;5m\]→\e[0m

Note, I do have some cursor positioning problems, though, when I scroll up and down through the command history.


* of a ThinkPad laptop

share|improve this answer
1  
Though it doesn't answer the question, this answer does give some nice usage examples. Thanks. –  dotancohen Apr 6 at 11:33

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.