138

The way my bash prompt is currently configured, it shows the whole path to the current directory. This is annoying when I'm deep inside a directory tree, as the prompt becomes so long that every command wraps into the next line. How do I make it show only the last part of the path?

This is what I have in my .bashrc:

PS1='${debian_chroot:+($debian_chroot)}\[\033[01;32m\]\u@\h\[\033[00m\]:\[\033[01;34m\]\w\[\033[00m\]\$ '

# If this is an xterm set the title to user@host:dir
case "$TERM" in
xterm*|rxvt*)
    PROMPT_COMMAND='echo -ne "\033]0;${USER}@${HOSTNAME}: ${PWD/$HOME/~}\007"'
    ;;
*)
    ;;
esac

8 Answers 8

187

Change the \w (lowercase) to \W (uppercase):

PS1='${debian_chroot:+($debian_chroot)}\[\033[01;32m\]\u@\h\[\033[00m\]:\[\033[01;34m\]\W\[\033[00m\]\$ '
                                                                                       ^^
           this one waaaaaay over here ------------------------------------------------+    

Have a look at the Bash Prompt HOWTO for lots of fun details. example:

user@host:/usr/local/bin$ echo $PS1
${debian_chroot:+($debian_chroot)}\[\033[01;31m\]\u@\h\[\033[00m\]:\[\033[01;36m\]\w\[\033[00m\]\$ 

user@host:/usr/local/bin$ export PS1='${debian_chroot:+($debian_chroot)}\[\033[01;31m\]\u@\h\[\033[00m\]:\[\033[01;36m\]\W\[\033[00m\]\$ '

user@host:bin$

The PROMPT_COMMAND variable, if set, is a command that gets run before displaying the prompt specified in PS1. In your case, PROMPT_COMMAND runs an echo statement with certain ANSI escape sequences that manipulate the titlebar of an Xterm.

If you suspect your PROMPT_COMMAND is overriding your PS1 prompt, you can unset it and test things out:

$ unset PROMPT_COMMAND

Finally, be sure that you're changing the PS1 definition that actually gets used. Common locations are /etc/bash.bashrc, /etc/profile, ~/.bashrc, ~/.bash_profile, ~/.profile. The system files are generally (but not always) run before the user files.

4
  • Hm... I'm afraid it's already \w, but it seems like that case statement overrides it when i'm on an xterm, and the problem seems to be with the PWD in the PROMPT_COMMAND line. Do you know what I should put there? Oct 25, 2009 at 22:48
  • 4
    \w (lower case) sets it to full path, \W (uppercase) trims to the final bit. the PROMPT_COMMAND is setting the window title in an xterm. check your TERM variable; if it doesn't start with "xterm" or "rxvt" then PROMPT_COMMAND isn't even getting run. Oct 25, 2009 at 22:59
  • Oh, yeah, duh. Sorry, I mixed upper and lowercase. That worked. Thanks! :) Oct 25, 2009 at 23:39
  • Great answer. Make sure you reboot in order this to take effect. Thanks!
    – Combine
    May 31, 2018 at 9:00
31

Simple bash replace command is

${VAR/pattern_to_find/pattern_to_replace}

For showing the last directory you can just do ${PWD/*\//}, i.e. find any thing before and including the last '/' and replace it with nothing.

On my ubuntu machine I use:

export PS1='$(whoami):${PWD/*\//}#'. 
1
  • 1
    I like this answer better than the accepted one because it's generic to any situation instead of just the special parsing logic of $PS1. Fewer more powerful tools are easier to remember and compose. :)
    – user439795
    Jun 7, 2018 at 17:03
9

My solution is to show the top three and bottom 2 directories when there are more than 5

So my prompt (which has other info too) looks like:

08:38:42 durrantm U2017 /home/durrantm/Dropbox/_/rails/everquote

when my pwd is actually

/home/durrantm/Dropbox/93_2016/work/code/ruby__rails/rails/everquote

My PS1 prompt is setup as follows:

HOST='\[\033[02;36m\]\h'; HOST=' '$HOST
TIME='\[\033[01;31m\]\t \[\033[01;32m\]'
LOCATION=' \[\033[01;34m\]`pwd | sed "s#\(/[^/]\{1,\}/[^/]\{1,\}/[^/]\{1,\}/\).*\(/[^/]\{1,\}/[^/]\{1,\}\)/\{0,1\}#\1_\2#g"`'
BRANCH=' \[\033[00;33m\]$(git_branch)\[\033[00m\]\n\$ '
PS1=$TIME$USER$HOST$LOCATION$BRANCH

git_branch is a function which shows current git branch, I keep it in my dotfiles, it is:

git_branch () {
  git branch 2> /dev/null | sed -e '/^[^*]/d' -e 's/* \(.*\)/\1/'
  }
1
  • This is awesome! Thanks a lot for this answer.
    – Carlos F
    Sep 29, 2019 at 23:27
4

My solution for this is slightly different in regards to how do I export it, so thought I'd share it here:

Create another prompt string variable; PS5 and export the following string in your .profile / .bash_profile file:

\u: Display the current username .

\W: Print the base of current working directory.

# Display username and current directory only.
export PS5='export PS1="\u:\W$";';

Now whenever you need to use the shorthand-ed PS, just run: eval $PS5


Or even better yet, create an alias in your .bash_aliases file: (thanks to @muru)

alias PS5='export PS1="\u:\W$";';

source again, and now you can just type PS5 to switch.

1
  • 1
    This looks like a frankenalias. Why not just use an alias or a function?
    – muru
    Aug 19, 2018 at 1:31
1

I believe this option is much easier, by simply doing:

echo $PWD | rev | cut -d '/' -f 1 | rev

So assign this to the PS1 variable in your .bashrc file:

PS1='$(PWD | rev | cut -d '/' -f 1 | rev)'
1

Show only current directory name (not full path) on bash prompt

Most of the other solutions did not work for me across all of my OSes that share my dot files: AIX, Windoze, and Linux. The bash ports were old versions that didn't support certain constructs and I didn't want to fork another process (i.e. sed, awk, etc.) which is noticeably expensive under cygwin.

The following is long but performant:

# takes a number argument of the number of last dirs to show
function DIR_LAST {
    # read -a didn't seem to work under bash 3
    IFS='/' array=($PWD)
    len=${#array[@]}
    start=$((len - $1))
    # leading / if fewer dir args: /usr/flastname not usr/flastname
    if (( $start <= 1 )); then
        start=1
        echo -n /
    fi
    for (( i = $start; $i < $len; i++ )); do
        if (( $i > $start )); then
            echo -n /
        fi
        echo -n ${array[$i]}
    done
}
export PS1="\$(DIR_LAST 2) {$(hostname)} "

I want it to spit out:

/
/usr
/usr/foo
foo/bin

Notice the lack of a leading slash in the last line which is how I like it. Also, you can spit out the last 3 directories by changing the arg to DIR_LAST.

Also, I tried to do this with a regex and BASH_REMATCH but bash v3 didn't seem to like the parens and I couldn't figure out how to properly escape them. Sigh.

1
root:~/project#  -> root:~/project(dev)# 

add the following code to the end of your ~/.bashrc

force_color_prompt=yes
color_prompt=yes
parse_git_branch() {
git branch 2> /dev/null | sed -e '/^[^*]/d' -e 's/* \(.*\)/(\1)/'
}
if [ "$color_prompt" = yes ]; then
PS1='${debian_chroot:+($debian_chroot)}\[\033[01;32m\]\u@\h\[\033[00m\]:\[\033[01;34m\]\w\[\033[01;31m\]$(parse_git_branch)\[\033[00m\]\$ '
else
PS1='${debian_chroot:+($debian_chroot)}\u@\h:\w$(parse_git_branch)\$ '
fi
unset color_prompt force_color_prompt
1
export PS1="\[\e[32m\]\u@\h \[\e[37m\]\W \[\e[32m\]$"

Put the above line at the end of ~/.bashrc, and everything should go well. This will preserve the color and keeps things in beautiful way.

32m --> green

37m --> white

You must log in to answer this question.

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