Code challenge: Bash prompt path shortener

前端 未结 5 1389
爱一瞬间的悲伤
爱一瞬间的悲伤 2021-01-30 09:27

I implemented a prompt path shortener for bash to be included in the PS1 environment variable, which shortens the working directory into something more compact but still descrip

相关标签:
5条回答
  • 2021-01-30 09:55

    This was my own solution when I had the idea for this challenge. The inspiration actually came from Jolexa's Blog.

    So here it is, the ruby implementation in readable form:

    a = ARGV[1].gsub(%r{^#{ENV['HOME']}}, "~")
    b, a = a, a.gsub(%r{/(\.?[^/.])[^/]+(/.*)}, '/\1\2') while
      (a.length > ARGV[2].to_i) && (b != a)
    print a
    

    And the actual one-line implementation within the bash function:

    _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'
    }
    
    0 讨论(0)
  • 2021-01-30 10:09

    Pure Bash:

    _dir_chomp () {
        local IFS=/ c=1 n d
        local p=(${1/#$HOME/\~}) r=${p[*]}
        local s=${#r}
        while ((s>$2&&c<${#p[*]}-1))
        do
            d=${p[c]}
            n=1;[[ $d = .* ]]&&n=2
            ((s-=${#d}-n))
            p[c++]=${d:0:n}
        done
        echo "${p[*]}"
    }
    

    For purposes of testing, I'm assuming that the question means that the current user is "user1".

    Note: Bash 4 has a variable PROMPT_DIRTRIM that shortens the \w escape in PS1 by retaining the number of sub-directories according to its value and replacing the rest with ...

    /$ PROMPT_DIRTRIM=2
    /$ echo $PS1
    \w\$
    /$ pwd
    /
    /$ cd /usr/share/doc/bash
    .../doc/bash$
    
    0 讨论(0)
  • 2021-01-30 10:13

    This one is 20 or so characters shorter than my other answer:

    _dir_chomp () {
        local p=${1/#$HOME/\~} b s
        s=${#p}
        while [[ $p != "${p//\/}" ]]&&(($s>$2))
        do
            p=${p#/}
            [[ $p =~ \.?. ]]
            b=$b/${BASH_REMATCH[0]}
            p=${p#*/}
            ((s=${#b}+${#p}))
        done
        echo ${b/\/~/\~}${b+/}$p
    }
    
    0 讨论(0)
  • 2021-01-30 10:15

    This is how I shorten my bash prompt w/ full path in titlebar (works since 3.0):

    _PS1P=('' '..')
    PROMPT_COMMAND='_PS1L=${#DIRSTACK[0]} _PS1D=${DIRSTACK[0]}'
    PS1='\[\e]2;\h:\w\a\]\h ${_PS1P[$_PS1L>36]}${_PS1D:$_PS1L>36?-34:0} \$ '
    

    This method requires very low CPU overhead.

    0 讨论(0)
  • 2021-01-30 10:18

    Another solution with only bash internals, no use of sed

    shortpath()                                                                                                                                                                                                                                                                   
    {           
        dir=${1%/*} && last=${1##*/}                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                
    
        res=$(for i in ${dir//\// } ; do echo -n "${i:0:3}../" ; done)                                                                                                                                                                                                            
        echo "/$res$last"                                                                                                                                                                                                                                                         
    } 
    

    My previous solution, with bash and sed. it cut each dir in 3 first caracters and add '..' like this: /hom../obo../tmp../exa../bas../

    shortpath()
    {
            dir=$(dirname $1)
            last=$(basename $1)
    
            v=${dir//\// } # replace / by <space> in path
            t=$(printf "echo %s | sed -e 's/^\(...\).*$/\\\1../' ; " $v) 
                # prepare command line, cut names to 3 char and add '..'
            a=$(eval $t) 
                # a will contain list of 3 char words ended with '..' ans separated with ' '
    
            echo " "$a"/"$last | sed -e 's/ /\//g'
    }
    
    0 讨论(0)
提交回复
热议问题