Linux: My bash prompt

There seems to be a semi-meme going around on some of the planets I read.

My concern is long directory paths and I wanted a dymanic solution for it. Surely, I cannot be the first person to think of it, but I haven’t seen it in use anywhere else.

jolexa @ helios :: ~ %%
and
jolexa @ helios :: ~ %% cd projects/prefix-tinderbox/really_long_dirname_so_that_binpkgs_can_be_shortened/a/b/ jolexa @ helios :: .../a/b %%

(the colors and wrapping are representitive only)

and the code that produces that:

_chomp_path() {
    local path=${1/${HOME}/\~}
    local last=${path} sedout= count=0 count2=0
    sedout=$(echo ${path} | sed -e 's:/: :g')
    for i in ${sedout}; do
        (( count++ ))
    done
    if ((count > 2)); then
        last="..."
        for i in ${sedout}; do
        (( count2++ ))
        if (( count2 >=  count - 1 )); then
            last+="/$i"
        fi
        done
    fi
    echo ${last}
}

PS1='\[\033[1;34m\]\u \[\033[1;32m\]@\[\033[1;34m\] \h \[\033[1;30m\]::\[\033[1;37m\] $(_chomp_path $(pwd)) \[\033[1;30m\]%%\[\033[0m\] '

If anyone wants to improve that function, let me know. It “fails” on directories with spaces in it.

Leave a comment ?

16 Comments.

  1. Nice idea ;)

    I still prefer my two line solution though, that way I always know where to look for my prompt :p

  2. A nice one. I want to keep my prompt short so now it shows only last directory in path. Sometimes one dir is too little so when I’ll have some time I’ll try showing two like you do :)

  3. Florian (SuperFlo) CROUZAT

    As I told you on IRC, bash4 as a builtin setting for that: PROMPT_DIRTRIM.

    • Yea, that makes life alot simpler. So,


      PROMPT_DIRTRIM=2
      PS1='\[\033[1;34m\]\u \[\033[1;32m\]@\[\033[1;34m\] \h \[\033[1;30m\]::\[\033[1;37m\] \w \[\033[1;30m\]%%\[\033[0m\] '

      will deprecate my _chomp_path() function. I’ll check for bash version and keep the function for bash-3 boxes but that will become useless over time too. Anyway, thx!

  4. How about an ruby path shortener?

    ruby -e’a=”‘$(pwd)’”;b,a=a,a.gsub(%r{/([^/])[^/]+(/.*)},”/\\1\\2″)while(a.length>20)&&(b!=a);puts a’

    • Arrgh, the comment engine destroyed my quote signs… Just replace accordingly. Or does this work?

      ruby -e'a="'$(pwd)'";b,a=a,a.gsub(%r{/([^/])[^/]+(/.*)},"/\\1\\2")while(a.length>20)&&(b!=a);puts a'

    • And more improved:

      ruby -e'a="'$(pwd)'".gsub(%r{^'$HOME'},"~");b,a=a,a.gsub(%r{/([^/])[^/]+(/.*)},"/\\1\\2")while(a.length>15)&&(b!=a);puts a'

      I think I’ll go with that. :-)

    • Boils down to having:


      _dir_chomp() {
      ruby -e'a="'$1'".gsub(%r{^'$HOME'},"~");b,a=a,a.gsub(%r{/(\.?[^/.])[^/]+(/.*)},"/\\1\\2")while(a.length>'$2')&&(b!=a);print a'
      }

      From prompt (PS1) call with:


      $(_dir_chomp "$(pwd)" 20)

      for a max length of 20.

  5. Not sure if bash has something similar or not, but in zsh you can do PS1=”%2c” and it would print the last two directories. Just change the number to display the amount of trailing directories you want printed.

  6. Heres a bash 3 friendly (i think) space friendly version

    _chomp_path() {
    local path=${1/${HOME}/\~}
    local last=${path} sedout= count=0 path2=

    #bash is dumb, "${#path//[^'/']/}" fails.
    sedout="${path//[^'/']/}"
    count=${#sedout}
    if ((count > 2)); then
    last="..."
    path2=${path%/*}
    path2=${path2%/*}
    last+=${path//${path2}}
    fi
    echo ${last}
    }

  7. Fish has a similar prompt. it shows only the first letter of every directory but the last one, which is displayed entirely.

  8. The zsh prompt knows %<string< and similar commands to trim strings within the prompt and print dots for the omitted parts (BTW: zsh is much more convenient for interactive shell: All such interactive functions like prompts, completion, … are much more powerful – once properly configured).

    Another possibility is to use plain sh substitution which will make it work in a few lines.
    You might want to have a look at my bash and zsh prompt buried in the German forums which uses path shortening with changing colors for the omitted part (which is not directly possible with zsh) by means of sh substitution:
    http://forums.gentoo.org/viewtopic-p-4223650.html#4223650
    (to use it with zsh you must source the code using the lines at the end of the posting and set the option prompt_subst). The path cutting sequence is added into the PS1 code near the end of the function (after "if ${CUT}").

  9. The following awk code will work for arbitrary directory names. The number of directories to show has been parametrized.

    _chomp_path() {

    local path=${1/${HOME}/\~}

    awk -v path=”$path” -v limit=2 ‘BEGIN {
    dirparts = split(path,split_path,”/”)
    if ( dirparts-1 > limit ) {
    printf(“%s”,”…”)
    for (i=dirparts-limit+1;i<=dirparts;i++) {
    printf("/%s",split_path[i])
    }
    }
    else {
    printf("%",path)
    }
    }' /dev/null
    }

  10. Mhm, whenever I’m trying to use pwd instead of \w in my PS1 it’s never changing after a cd command.
    Also with a plain $(pwd) instead of $(_chomp_path $(pwd)).
    Any ideas?