Bash Prompt – Show Only Current and Parent Directory

bashprompt

I'm new to bash and would like my prompt to show something that in tcsh was trivial, yet after a good google search I still cannot do.

I would like my prompt to include only the current and parent directories like this:

/parent/currentdir $

In tcsh this is achieved by:

set prompt = "%C2 %"

However in bash so far I have only found that I have to parse pwd to obtain the same output.

Isn't there a simpler way, like doing:

export PS1="$(some_command) $" 

Best Answer

Bash's prompt control features are rather static. If you want more control, you can include variables in your prompt; make sure you haven't turned off the promptvars option.

PS1='${PWD#"${PWD%/*/*}/"} \$ '

Note the single quotes: the variable expansions must happen at the time the prompt is displayed, not at the time the PS1 variable is defined.

If you want more control over what is displayed, you can use command substitutions. For example, the snippet above loses the ~ abbreviation for the home directory.

PS1='$(case $PWD in
        $HOME) HPWD="~";;
        $HOME/*/*) HPWD="${PWD#"${PWD%/*/*}/"}";;
        $HOME/*) HPWD="~/${PWD##*/}";;
        /*/*/*) HPWD="${PWD#"${PWD%/*/*}/"}";;
        *) HPWD="$PWD";;
      esac; printf %s "$HPWD") \$ '

This code is rather cumbersome, so instead of sticking it into the PS1 variable, you can use the PROMPT_COMMAND variable to run code to set HPWD and then use that in your prompt.

PROMPT_COMMAND='case $PWD in
        $HOME) HPWD="~";;
        $HOME/*/*) HPWD="${PWD#"${PWD%/*/*}/"}";;
        $HOME/*) HPWD="~/${PWD##*/}";;
        /*/*/*) HPWD="${PWD#"${PWD%/*/*}/"}";;
        *) HPWD="$PWD";;
      esac'
PS1='$HPWD \$'

Since the shortened prompt only changed on a directory change, you don't need to recalculate it each time a prompt is displayed. Bash doesn't provide a hook that runs on a current directory change, but you can simulate it by overriding cd and its cousins.

cd () { builtin cd "$@" && chpwd; }
pushd () { builtin pushd "$@" && chpwd; }
popd () { builtin popd "$@" && chpwd; }
chpwd () {
  case $PWD in
    $HOME) HPWD="~";;
    $HOME/*/*) HPWD="${PWD#"${PWD%/*/*}/"}";;
    $HOME/*) HPWD="~/${PWD##*/}";;
    /*/*/*) HPWD="${PWD#"${PWD%/*/*}/"}";;
    *) HPWD="$PWD";;
  esac
}
PS1='$HPWD \$'

Note that you don't need to, and should not, export PS1, since it's a shell setting, not an environment variable. A bash PS1 setting wouldn't be understood by other shells.

P.S. If you want a nice interactive shell experience, switch to zsh, where all of these (prompt % expansions largely encompassing tcsh's, chpwd, etc.) are native features.

PS1='%2~ %# '
Related Question