44

Here's my PS1 variable:

PS1='\u:\W$(__git_ps1 "\e[32m\][%s]\e[0m\]")$ '

Works great for picking up my Git branch, but it has the unfortunate side-effect of wrapping the lines when the colours are active, so that they overlap when you use long commands.

Can anyone with magic PS1 skills help me out to fix this?

wjandrea
  • 28,235
  • 9
  • 60
  • 81
Aupajo
  • 5,885
  • 6
  • 30
  • 28

3 Answers3

66

Got it, needed to escape the colours properly.

Fix:

PS1='\u:\W$(__git_ps1 "\[\e[32m\][%s]\[\e[0m\]")$ '
Aupajo
  • 5,885
  • 6
  • 30
  • 28
  • 14
    And for those too lazy to do a diff, terminal escapes should be surrounded by `\[` `\]` in order for bash to be able to correctly count printing characters to the beginning of the line. http://manpages.ubuntu.com/manpages/precise/en/man1/bash.1.html#contenttoc26 – A B Jun 27 '13 at 00:31
  • Aupajo, I'm having a similar problem, using a generated PS1. I don't know enough to see what's not being escaped properly. Any suggestions? My command is: `export PS1="\[\e[0;40m\]\h:\W \u\033[0;32m \$(parse_git_branch)\[\e[0m\]$ "` – karl Aug 13 '13 at 17:42
  • 1
    @karl I think you need to escape and/or close the bracket around `\033[0;`, but I could be wrong. You might find it easier to start with a working one and modify it. – Aupajo Aug 27 '13 at 23:22
  • 2
    Yeah, I played around with it a bit and eventually stumbled into the right answer. I also switched to using `\e[` instead of `\[\033[`, which makes it easier to read. – karl Aug 28 '13 at 00:15
  • i dont see the difference between the original and this ? – nikoss Mar 29 '19 at 17:38
  • here is the reason why: https://unix.stackexchange.com/a/157884/77353 – Wang Sep 09 '22 at 16:10
30

May I suggest the following method for colors in Bash, it makes the code much more readable and alot harder for you to miss an escape or two.

Put the following in your ~/.bashrc

BLACK=$(tput setaf 0)
RED=$(tput setaf 1)
GREEN=$(tput setaf 2)
LIME_YELLOW=$(tput setaf 190)
YELLOW=$(tput setaf 3)
POWDER_BLUE=$(tput setaf 153)
BLUE=$(tput setaf 4)
MAGENTA=$(tput setaf 5)
CYAN=$(tput setaf 6)
WHITE=$(tput setaf 7)
BRIGHT=$(tput bold)
NORMAL=$(tput sgr0)
BLINK=$(tput blink)
REVERSE=$(tput smso)
UNDERLINE=$(tput smul)

A sample PS1 (or really anything that prints to the screen) would be:

 PS1="\[${WHITE}\](\[${YELLOW}\]\u@\h\[${WHITE}\])\[${NORMAL}\]$ "

You need only put \[ \] around the color words.

If you have a 256-color terminal, you can experiment with other numerical values to 'tput setaf' all the way up to 255.

SiegeX
  • 135,741
  • 24
  • 144
  • 154
  • 1
    Oh that is simple, clear, and awesome. Have some rep, on the house. – Aupajo Nov 20 '09 at 02:37
  • 1
    Much more generic solution to the problem, helped fix my problem in seconds! – The Pjot Jul 16 '18 at 11:59
  • Reset is really useful too `RESET=$(tput sgr0)`... that said, this is slowish – Ray Foss Nov 11 '20 at 21:15
  • This solution worked for me to +1. @SiegeX can you yes `\[` and `\]` inside the assignment at the beginning itself instead of at PS1? `BLACK="\[$(tput setaf 0)\]"` will this work properly? – Raveen Kumar Jan 06 '22 at 11:57
6

These are the color functions I use regularly... wrote them years ago and have gotten so used to them that they're a regular part of my scripting. Just stick this code block into your .bashrc file, start a new session, and you're set!

I use these as colorful/stylish printf replacements:

## ∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞ ##
## ∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞ [ Aesthir's Color Functions ] ∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞ ##
## ∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞ ##
Normal () { printf '\e[m'"$*"; }                  ; Tblack () { printf '\e[0;30m'"$*"'\e[m'; }
TNormal () { printf '\e[m'"$*"; }                 ; Tred () { printf '\e[0;31m'"$*"'\e[m'; }
Bold () { printf '\e[1m'"$*"'\e[m'; }             ; Tgreen () { printf '\e[0;32m'"$*"'\e[m'; }
TBold () { printf '\e[1m'"$*"'\e[m'; }            ; Tbrown () { printf '\e[0;33m'"$*"'\e[m'; }
Underline () { printf '\e[4m'"$*"'\e[m'; }        ; Tyellow () { printf '\e[0;33m'"$*"'\e[m'; }
TUnderline () { printf '\e[4m'"$*"'\e[m'; }       ; Tblue () { printf '\e[0;34m'"$*"'\e[m'; }
Flash () { printf '\e[5m'"$*"'\e[m'; }            ; Tmagenta () { printf '\e[0;35m'"$*"'\e[m'; }
TFlash () { printf '\e[5m'"$*"'\e[m'; }           ; Tpurple () { printf '\e[0;35m'"$*"'\e[m'; }
Invert () { printf '\e[7m'"$*"'\e[m'; }           ; Taqua () { printf '\e[0;36m'"$*"'\e[m'; }
TInvert () { printf '\e[7m'"$*"'\e[m'; }          ; Tcyan () { printf '\e[0;36m'"$*"'\e[m'; }
Invisible () { printf '\e[8m'"$*"'\e[m'; }        ; Tgrey () { printf '\e[0;37m'"$*"'\e[m'; }
TInvisible () { printf '\e[8m'"$*"'\e[m'; }       ; Twhite () { printf '\e[0;37m'"$*"'\e[m'; }
## ∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞ Bold Color Text ∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞ ## ∞∞∞∞∞∞∞∞∞∞∞∞ Underlined Color Text ∞∞∞∞∞∞∞∞∞∞∞∞∞ ##
TblackB () { printf '\e[1;30m'"$*"'\e[m'; }       ; TblackU () { printf '\e[4;30m'"$*"'\e[m'; }
TgreyB () { printf '\e[1;30m'"$*"'\e[m'; }        ; TredU () { printf '\e[4;31m'"$*"'\e[m'; }
TredB () { printf '\e[1;31m'"$*"'\e[m'; }         ; TgreenU () { printf '\e[4;32m'"$*"'\e[m'; }
TgreenB () { printf '\e[1;32m'"$*"'\e[m'; }       ; TbrownU () { printf '\e[4;33m'"$*"'\e[m'; }
TbrownB () { printf '\e[1;33m'"$*"'\e[m'; }       ; TyellowU () { printf '\e[4;33m'"$*"'\e[m'; }
TyellowB () { printf '\e[1;33m'"$*"'\e[m'; }      ; TblueU () { printf '\e[4;34m'"$*"'\e[m'; }
TblueB () { printf '\e[1;34m'"$*"'\e[m'; }        ; TmagentaU () { printf '\e[4;35m'"$*"'\e[m'; }
TmagentaB () { printf '\e[1;35m'"$*"'\e[m'; }     ; TpurpleU () { printf '\e[4;35m'"$*"'\e[m'; }
TpurpleB () { printf '\e[1;35m'"$*"'\e[m'; }      ; TaquaU () { printf '\e[4;36m'"$*"'\e[m'; }
TaquaB () { printf '\e[1;36m'"$*"'\e[m'; }        ; TcyanU () { printf '\e[4;36m'"$*"'\e[m'; }
TcyanB () { printf '\e[1;36m'"$*"'\e[m'; }        ; TgreyU () { printf '\e[4;37m'"$*"'\e[m'; }
TwhiteB () { printf '\e[1;37m'"$*"'\e[m'; }       ; TwhiteU () { printf '\e[4;37m'"$*"'\e[m'; }
## ∞∞∞∞∞∞∞∞∞∞∞∞∞ Flashing Color Text ∞∞∞∞∞∞∞∞∞∞∞∞∞∞ ## ∞∞∞∞∞∞∞∞∞∞∞∞∞ Inverted Color Text ∞∞∞∞∞∞∞∞∞∞∞∞∞∞ ##
TblackF () { printf '\e[5;30m'"$*"'\e[m'; }       ; TblackI () { printf '\e[7;40m'"$*"'\e[m'; }
TredF () { printf '\e[5;31m'"$*"'\e[m'; }         ; TredI () { printf '\e[7;41m'"$*"'\e[m'; }
TgreenF () { printf '\e[5;32m'"$*"'\e[m'; }       ; TgreenI () { printf '\e[7;42m'"$*"'\e[m'; }
TbrownF () { printf '\e[5;33m'"$*"'\e[m'; }       ; TbrownI () { printf '\e[7;43m'"$*"'\e[m'; }
TyellowF () { printf '\e[5;33m'"$*"'\e[m'; }      ; TyellowI () { printf '\e[7;43m'"$*"'\e[m'; }
TblueF () { printf '\e[5;34m'"$*"'\e[m'; }        ; TblueI () { printf '\e[7;44m'"$*"'\e[m'; }
TmagentaF () { printf '\e[5;35m'"$*"'\e[m'; }     ; TmagentaI () { printf '\e[7;45m'"$*"'\e[m'; }
TpurpleF () { printf '\e[5;35m'"$*"'\e[m'; }      ; TpurpleI () { printf '\e[7;45m'"$*"'\e[m'; }
TaquaF () { printf '\e[5;36m'"$*"'\e[m'; }        ; TaquaI () { printf '\e[7;46m'"$*"'\e[m'; }
TcyanF () { printf '\e[5;36m'"$*"'\e[m'; }        ; TcyanI () { printf '\e[7;46m'"$*"'\e[m'; }
TgreyF () { printf '\e[5;37m'"$*"'\e[m'; }        ; TgreyI () { printf '\e[7;47m'"$*"'\e[m'; }
TwhiteF () { printf '\e[5;37m'"$*"'\e[m'; }       ; TwhiteI () { printf '\e[7;47m'"$*"'\e[m'; }
## ∞∞∞∞∞∞∞∞∞∞∞∞∞ Invisible Color Text ∞∞∞∞∞∞∞∞∞∞∞∞∞ ## ∞∞∞∞∞∞∞∞ Plain Text on Color Background ∞∞∞∞∞∞∞∞ ##
TblackV () { printf '\e[8;30m'"$*"'\e[m'; }       ; Bblack () { printf '\e[m'"$*"'\e[m'; }
TredV () { printf '\e[8;31m'"$*"'\e[m'; }         ; Bred () { printf '\e[0;41m'"$*"'\e[m'; }
TgreenV () { printf '\e[8;32m'"$*"'\e[m'; }       ; Bgreen () { printf '\e[0;42m'"$*"'\e[m'; }
TbrownV () { printf '\e[8;33m'"$*"'\e[m'; }       ; Bbrown () { printf '\e[0;43m'"$*"'\e[m'; }
TyellowV () { printf '\e[8;33m'"$*"'\e[m'; }      ; Byellow () { printf '\e[0;43m'"$*"'\e[m'; }
TblueV () { printf '\e[8;34m'"$*"'\e[m'; }        ; Bblue () { printf '\e[0;44m'"$*"'\e[m'; }
TmagentaV () { printf '\e[8;35m'"$*"'\e[m'; }     ; Bmagenta () { printf '\e[0;45m'"$*"'\e[m'; }
TpurpleV () { printf '\e[8;35m'"$*"'\e[m'; }      ; Bpurple () { printf '\e[0;45m'"$*"'\e[m'; }
TaquaV () { printf '\e[8;36m'"$*"'\e[m'; }        ; Baqua () { printf '\e[0;46m'"$*"'\e[m'; }
TcyanV () { printf '\e[8;36m'"$*"'\e[m'; }        ; Bcyan () { printf '\e[0;46m'"$*"'\e[m'; }
TgreyV () { printf '\e[8;37m'"$*"'\e[m'; }        ; Bgrey () { printf '\e[0;47m'"$*"'\e[m'; }
TwhiteV () { printf '\e[8;37m'"$*"'\e[m'; }       ; Bwhite () { printf '\e[0;47m'"$*"'\e[m'; }
## ∞∞∞∞∞∞∞∞∞ Bold Text on Color Background ∞∞∞∞∞∞∞∞ ## ∞∞∞∞∞∞ Underlined Text on Color Background ∞∞∞∞∞ ##
BblackB () { printf '\e[1;40m'"$*"'\e[m'; }       ; BblackU () { printf '\e[4;40m'"$*"'\e[m'; }
BredB () { printf '\e[1;41m'"$*"'\e[m'; }         ; BredU () { printf '\e[4;41m'"$*"'\e[m'; }
BgreenB () { printf '\e[1;42m'"$*"'\e[m'; }       ; BgreenU () { printf '\e[4;42m'"$*"'\e[m'; }
BbrownB () { printf '\e[1;43m'"$*"'\e[m'; }       ; BbrownU () { printf '\e[4;43m'"$*"'\e[m'; }
ByellowB () { printf '\e[1;43m'"$*"'\e[m'; }      ; ByellowU () { printf '\e[4;43m'"$*"'\e[m'; }
BblueB () { printf '\e[1;44m'"$*"'\e[m'; }        ; BblueU () { printf '\e[4;44m'"$*"'\e[m'; }
BmagentaB () { printf '\e[1;45m'"$*"'\e[m'; }     ; BmagentaU () { printf '\e[4;45m'"$*"'\e[m'; }
BpurpleB () { printf '\e[1;45m'"$*"'\e[m'; }      ; BpurpleU () { printf '\e[4;45m'"$*"'\e[m'; }
BaquaB () { printf '\e[1;46m'"$*"'\e[m'; }        ; BaquaU () { printf '\e[4;46m'"$*"'\e[m'; }
BcyanB () { printf '\e[1;46m'"$*"'\e[m'; }        ; BcyanU () { printf '\e[4;46m'"$*"'\e[m'; }
BgreyB () { printf '\e[1;47m'"$*"'\e[m'; }        ; BgreyU () { printf '\e[4;47m'"$*"'\e[m'; }
BwhiteB () { printf '\e[1;47m'"$*"'\e[m'; }       ; BwhiteU () { printf '\e[4;47m'"$*"'\e[m'; }
## ∞∞∞∞∞∞∞ Flashing Text on Color Background ∞∞∞∞∞∞ ## ∞∞∞∞∞∞∞ Inverted Text on Color Background ∞∞∞∞∞∞ ##
BblackF () { printf '\e[5;40m'"$*"'\e[m'; }       ; BblackI () { printf '\e[7;30m'"$*"'\e[m'; }
BredF () { printf '\e[5;41m'"$*"'\e[m'; }         ; BredI () { printf '\e[7;31m'"$*"'\e[m'; }
BgreenF () { printf '\e[5;42m'"$*"'\e[m'; }       ; BgreenI () { printf '\e[7;32m'"$*"'\e[m'; }
BbrownF () { printf '\e[5;43m'"$*"'\e[m'; }       ; BbrownI () { printf '\e[7;33m'"$*"'\e[m'; }
ByellowF () { printf '\e[5;43m'"$*"'\e[m'; }      ; ByellowI () { printf '\e[7;33m'"$*"'\e[m'; }
BblueF () { printf '\e[5;44m'"$*"'\e[m'; }        ; BblueI () { printf '\e[7;34m'"$*"'\e[m'; }
BmagentaF () { printf '\e[5;45m'"$*"'\e[m'; }     ; BmagentaI () { printf '\e[7;35m'"$*"'\e[m'; }
BpurpleF () { printf '\e[5;45m'"$*"'\e[m'; }      ; BpurpleI () { printf '\e[7;35m'"$*"'\e[m'; }
BaquaF () { printf '\e[5;46m'"$*"'\e[m'; }        ; BaquaI () { printf '\e[7;36m'"$*"'\e[m'; }
BcyanF () { printf '\e[5;46m'"$*"'\e[m'; }        ; BcyanI () { printf '\e[7;36m'"$*"'\e[m'; }
BgreyF () { printf '\e[5;47m'"$*"'\e[m'; }        ; BgreyI () { printf '\e[7;37m'"$*"'\e[m'; }
BwhiteF () { printf '\e[5;47m'"$*"'\e[m'; }       ; BwhiteI () { printf '\e[7;37m'"$*"'\e[m'; }
## ∞∞∞∞∞∞ Invisible Text on Color Background ∞∞∞∞∞∞ ## ∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞ Color Code Notes ∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞ ##
BblackV () { printf '\e[8;40m'"$*"'\e[m'; }     ## Unless I missed something or made a mistake, I   ##
BredV () { printf '\e[8;41m'"$*"'\e[m'; }       ## calculate a total of 7681 different color codes, ##
BgreenV () { printf '\e[8;42m'"$*"'\e[m'; }     ## none of which produce a duplicate result.        ##
BbrownV () { printf '\e[8;43m'"$*"'\e[m'; }     ##                      These will be fine for now. ##
ByellowV () { printf '\e[8;43m'"$*"'\e[m'; }
BblueV () { printf '\e[8;44m'"$*"'\e[m'; }
BmagentaV () { printf '\e[8;45m'"$*"'\e[m'; }
BpurpleV () { printf '\e[8;45m'"$*"'\e[m'; }
BaquaV () { printf '\e[8;46m'"$*"'\e[m'; }
BcyanV () { printf '\e[8;46m'"$*"'\e[m'; }
BgreyV () { printf '\e[8;47m'"$*"'\e[m'; }
BwhiteV () { printf '\e[8;47m'"$*"'\e[m'; }
## ∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞∞ ##
``

The only thing to keep in mind is when wanting a % percent sign or a \ backslash, you need to double them up inside:
like: printf "$(Tblue "%%s")\n" 'hi'
but not for Tblue "%s\n" 'hi'
or printf "$(Tblue "%s" 'hi')\n"

Since these use printf, you can do stuff like:

 printf "hi $(Tred there) man $(BaquaI "%c" '!') $(Bold 'This \\t is %%s') %s\n" "$(BgreenB 'super')" "$(Bblue mega Colorful)"
or in an echo:
 echo "hi $(Tred there) man $(BaquaI "%c" '!') $(Bold 'This \\t is %s' "$(BblackB 'super')") $(Bblue mega Colorful)"
A more useful example:
printf "\t%s Volume \"%s\" is not connected.\n" "$(TwhiteB [)$(TredB Error)$(TwhiteB \]:)" "$(Tbrown $Volume)"
Or with other commands:
eval "echo 'This is OSX' | sed 's:OSX:$(Invert [)$(TaquaF OSX)$(Invert ]):'"
Or something with a bit more swank:
find . -exec stat -f "Name: $(Tbrown %%N)%t%t$(Tpurple "->")%tPermissions: $(Tgreen %%Sp)" {} \;

Use your imagination! Feel free all to use these... the only thing I ask is if someone out there types up more of them, mix/matching them, like TcyanBgreenUI, or make up your own names... can you please post them for me and let me know about the post? or email them to me at aesth1r@me.com. I'm too lazy to type up all possibilities.

Enjoy!

-- Aesthir

Aesthir
  • 347
  • 5
  • 12
  • 4
    Thanks for sharing this awesome work -- unfortunately it has the same issue as OP's original, which is that the Bash prompt specifically needs the `\[` and `\]` sequences in order to calculate the right string length. Unfortunately I haven't been able to find a way to provide those sequences properly from within a printf statement. – Siobhán Nov 16 '13 at 02:10
  • 2
    Ah, okay, I finally found a way to use functions like these with the right escape sequences for a command prompt. Instead of trying to come up with a single string for $PS1 that always works, I defined a function that rebuilds the prompt each time, and added that to $PROMPT_COMMAND. e.g.: `TredB () { echo -n "\[\e[1;31m\]$*\[\e[m\]"; }` `build_prompt () { PS1="$(TredB \\w) #"; }` `PROMPT_COMMAND="${PROMPT_COMMAND} build_prompt;"` – Siobhán Nov 16 '13 at 07:37