31

I would love to have a readable colored path. For example, instead of simply using %~ to return ~/path/to/foo I would like to format it to ~$RED/$NOCOLORpath$RED/$NOCOLORto$RED/$NOCOLORfoo to highlight the path separators.

Can I define the content of PROMPT so that the path expression gets re-evaluated on each display? Something like ${${(%):-%~}//\//_some_format_expression/} obviously does not work.

Or should I hack this further, and force the PROMPT value to get reset each time we're changing a directory?

Any solution achieving the path formatting goal would be welcome.

Thanks :)

1
  • if you still exist you might want to mark a best answer for this :) May 19, 2010 at 0:46

4 Answers 4

41

zsh

Try this:

setopt PROMPT_SUBST
PROMPT='%{$(pwd|grep --color=always /)%${#PWD}G%} %(!.%F{red}.%F{cyan})%n%f@%F{yellow}%m%f%(!.%F{red}.)%#%f '

Here's a breakdown of the prompt:

  • PROMPT_SUBST turns on command substitution in the prompt (and parameter expansion and arithmetic expansion)
  • %{...%} - an escape sequence
  • $(pwd|grep --color=always /) - print the current directory and highlight the / - the color will depend on the $GREP_COLORS environment variable (or its default value) - bold red is the default
  • %${#PWD}G - use the length in characters of the name of the current directory as a glitch value. This makes the shell consider this the length of the preceding character sequence ( after the "%{" ) instead of the actual length of the string which includes ANSI escape sequences. This keeps the shell from being confused about the position of the cursor relative to the end of the prompt.
    - - - - - - - this is the end of the part that answers your question - - - - - - -
  • %(!.%F{red}.%F{cyan}) - if this is a privileged shell (root) set the foreground color to red, otherwise cyan
  • %n - output the username
  • %f - reset the foreground color to the default
  • @ - a literal at sign
  • %F{yellow} - make the foreground color yellow
  • %m - output the hostname
  • %f - reset the foreground color to the default
  • %(!.%F{red}.) - if this is a privileged shell (root) set the foreground color to red
  • %# - output a # for a privileged shell or % for an unprivileged one
  • %f - reset the foreground color to the default

I put the path first in this prompt for emphasis, since the question concerns the path.

alt text

Here is a version for zsh that changes the slash color depending on whether you are root (privileged) by manipulating the $GREP_COLORS variable:

setopt PROMPT_SUBST
PROMPT='%{$(pwd|([[ $EUID == 0 ]] && GREP_COLORS="mt=01;31" grep --color=always /|| GREP_COLORS="mt=01;34" grep --color=always /))%${#PWD}G%} %(!.%F{red}.%F{cyan})%n%f@%F{yellow}%m%f%(!.%F{red}.)%#%f '

Bash

You can do a similar prompt in Bash. In this example, I've put the user and hostname first and the color of the slashes also changes when the UID is 0. Warning: this overwrites Bash's $PS1 prompt variable. That shouldn't be a problem unless you're doing something special or you expect the behavior to change when you set that variable directly and this is in effect. Also, this uses a variable called "usercolor" which may collide with something else, although this whole thing could be put in a function and the variable declared local.

PROMPT_COMMAND='usercolor="\[\033[0;36m\]";[[ $EUID == 0 ]] && usercolor="\[\033[1;31m\]";PS1="$(pwd)";PS1="$usercolor\u\[\033[0m\]@\[\033[0;33m\]\h\[\033[0m\]:${PS1//\//$usercolor/\[\033[0m\]}$usercolor\\$\[\033[0m\] "'

alt text

I took advantage of the fact that Bash doesn't have zsh's "glitch" feature to use parameter expansion substitution to conditionally color the slashes (instead of using grep).

10
  • call me stupid, but the only wrong part I had was the use of double quotes instead of single quotes in the PROMPT definition. Thanks :) Oct 30, 2009 at 9:05
  • @NicDumZ, funny, I spent about 20 minutes on that problem elsewhere yesterday :) May 19, 2010 at 0:32
  • 1
    this is massively (geeky and) cool. Thanks... May 19, 2010 at 0:46
  • Any idea how to do this in Bash, or why it doesn't work in Bash? For me with Bash it just gets stuck at the first directory I start my terminal in, and doesn't update when I move around. I just took the $(pwd|grep --color=always /) and put that in my PS1 and got the strange behavior. Edit: OH! Didn't see the Bash section lol.
    – Ibrahim
    Nov 22, 2012 at 4:29
  • Actually, I'm trying to use your PS1 trick for Bash in my more complex prompt and it's not working, my PWD gets stuck again. But your snippet works as is. What's the purpose of PROMPT_COMMAND? This is what I've got: PS1="$(pwd)"; PS1="${debian_chroot:+($debian_chroot)}\[$bldgrn\]\u@$(fgcolor $hostnamecolor)\h$(resetcolor)\[$txtrst\]:\[$bldblu\]${PS1//\//$txtred/$bldblu}\[\e[00m\]$bldred\$(parse_git_branch)\[$txtrst\] \[$undcyn\]\T \d\[$txtrst\] 95\$ " colors defined in github.com/ibrahima/dotfiles/blob/master/.bashrc.d/prompt.sh
    – Ibrahim
    Nov 22, 2012 at 4:44
5

A pure zsh solution:

PROMPT='%n@%m: %{$PR_BOLD_RED%}${${(%):-%~}//\//${PR_BOLD_RED}/%f}%f '
  • ${(%):-%~} is the current path.
  • ${xxxxx//\//${PR_BOLD_RED}/%f} replaces every / in xxxxx by a bold red colored one
  • and of course PROMPT_SUBST has to be on.

I had be using double quotes in my tests, which does not allow substitution. Everything works fine with single quotes.

2
  • You must have $PR_BOLD_RED defined elsewhere. I have to use PROMPT='%n@%m: %{%B%F{red}%}${${(%):-%~}//\//%B%F{red\}/%b%f}%b%f ' including the very weird escaping of the closing curly brace (only) after the second "red". Oct 30, 2009 at 11:47
  • yes, I use Aaron Toponce's namings pthree.org/wp-content/uploads/2009/03/zsh_prompt which I found useful. Besides that, I dont have to escape anything, it works as provided. Nov 1, 2009 at 12:44
4

After some going-around, I can provide a solution overriding chpwd:

doprompt() {
  local my_path=${(%):-%~}
  PROMPT="${yourstuff}${my_path//\//${PR_BOLD_RED}/${reset_color}}${otherstuff}"
}
doprompt

chpwd() {
  doprompt
  # unrelated: set window title
  [[ -t 1 ]] || return;
  print -Pn "\e]2;%n@%m: %~\a";
}
  • Is there is a way to improve this code to get rid of the temporary my_path var? I can't directly replace the / inside %~ ...
  • Any solution using a dynamic syntax to avoid calling on each directory change doprompt is probably cleaner.
0

Here is my attempt (based on NicDumZ's):

setopt PROMPT_SUBST
# red, green, yellow, blue, magenta, cyan, white, black
# B (bold), K(background color), F(foreground color)

function doprompt {
# this is just the directory (%d could be %~ -- I prefer full path always)
PROMPT='%F{yellow}${${(%):-%d}//\//%F{magenta\}%B/%b%F{yellow\}}%f'
}

function chpwd() {
    doprompt
}

The difference is that I am using colored path, so I need to return to my original color for the path once the slash gets colored. In my case the path is normally yellow, and the slash gets colored with magenta, then it returns to yellow. I also prefer using %F%f sequences as they appear much more readable for me.

1
  • In which file you are adding the code?
    – Manish
    Sep 23, 2021 at 5:54

You must log in to answer this question.

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