代码挑战:Bash 提示路径缩短器

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/3497885/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-17 22:30:35  来源:igfitidea点击:

Code challenge: Bash prompt path shortener

bashpathprompt

提问by hurikhan77

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 descriptive. I'm curious what other ideas may exist.

我为将 bash 包含在 PS1 环境变量中实现了一个提示路径缩短器,它将工作目录缩短为更紧凑但仍具有描述性的内容。我很好奇还有什么其他想法可能存在。

Here's the challenge:

这是挑战:

Create a bash function _dir_chompwhich can be included into PS1 like this (line breaks inserted for readability):

创建一个_dir_chomp可以像这样包含在 PS1 中的 bash 函数(插入换行符以提高可读性):

PS1='\[3[01;32m\]\u@\h\[3[01;34m\] $(
  _dir_chomp "$(pwd)" 20
)\[3[01;37m\]$(parse_git_branch)\[3[01;34m\] $\[3[00m\] '

with "20" being the parameter for the maximum length as soft limit. These are the examples:

其中“20”是最大长度的参数作为软限制。这些是示例:

  1. /usr/portage/media-plugins/banshee-community-extensions/filesbecomes /u/p/m/b/files
  2. /home/user1/media/video/music/live-setsbecomes ~/m/v/m/live-sets(note the ~ character as replacement for $HOME)
  3. /home/user2/mediadoes NOT change (20 char limit not exceeded)
  4. /home/user1/this-is-a-very-long-path-name-with-more-than-20-charsbecomes ~/this-is-a-very-long-path-name-with-more-than-20-chars(last component stays unshortened: soft limit)
  5. /home/user1/srcbecomes ~/src($HOME always shortened)
  6. /home/user1/.kde4/share/config/kresourcesbecomes ~/.k/s/c/kresources(note the prefixing dot is preserved)
  1. /usr/portage/media-plugins/banshee-community-extensions/files变成 /u/p/m/b/files
  2. /home/user1/media/video/music/live-sets变成~/m/v/m/live-sets(注意 ~ 字符作为 $HOME 的替代)
  3. /home/user2/media不改变(不超过 20 个字符的限制)
  4. /home/user1/this-is-a-very-long-path-name-with-more-than-20-chars变为~/this-is-a-very-long-path-name-with-more-than-20-chars(最后一个组件保持不变:软限制)
  5. /home/user1/src变成~/src($HOME 总是缩短)
  6. /home/user1/.kde4/share/config/kresources变成~/.k/s/c/kresources(注意前缀点被保留)

Current user is user1.

当前用户是user1。

It's allowed to call external interpreters like awk, perl, ruby, pythonbut not compiled C programs or similar. In other words: external source files are not allowed, code must be inline. Shortest version wins. The length of the bash function body (and called sub functions) counts, means:

允许调用外部解释器,如awk, perl, rubypython但不允许调用已编译的 C 程序或类似程序。换句话说:不允许使用外部源文件,代码必须是内联的。最短的版本获胜。bash 函数体(和调用的子函数)的长度很重要,意味着:

_sub_helper() {
  # this counts
}
_dir_chomp() {
  # these characters count (between { and })
  _sub_helper "foobar" # _sub_helper body counts, too
}

回答by Paused until further notice.

Pure Bash:

纯重击:

_dir_chomp () {
    local IFS=/ c=1 n d
    local p=(${1/#$HOME/\~}) r=${p[*]}
    local s=${#r}
    while ((s>&&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".

出于测试目的,我假设该问题意味着当前用户是“user1”。

Note: Bash 4 has a variable PROMPT_DIRTRIMthat shortens the \wescape in PS1by retaining the number of sub-directories according to its value and replacing the rest with ...

注意:击4具有可变PROMPT_DIRTRIM在于缩短\w在逃逸PS1通过根据其值保留子目录的数目,并与更换其余...

/$ PROMPT_DIRTRIM=2
/$ echo $PS1
\w$
/$ pwd
/
/$ cd /usr/share/doc/bash
.../doc/bash$

回答by Paused until further notice.

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

这个比我的另一个答案短 20 个左右的字符:

_dir_chomp () {
    local p=${1/#$HOME/\~} b s
    s=${#p}
    while [[ $p != "${p//\/}" ]]&&(($s>))
    do
        p=${p#/}
        [[ $p =~ \.?. ]]
        b=$b/${BASH_REMATCH[0]}
        p=${p#*/}
        ((s=${#b}+${#p}))
    done
    echo ${b/\/~/\~}${b+/}$p
}

回答by hurikhan77

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

当我有这个挑战的想法时,这是我自己的解决方案。灵感其实来自Jolexa的博客

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

所以这里是可读形式的 ruby​​ 实现:

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

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

以及 bash 函数中的实际单行实现:

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

回答by obor

Another solution with only bash internals, no use of sed

另一个只有 bash 内部结构的解决方案,不使用 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../

我以前的解决方案,使用 bash 和 sed。它将每个目录切成 3 个第一个字符并添加“..”,如下所示:/hom../obo../tmp../exa../bas../

shortpath()
{
        dir=$(dirname )
        last=$(basename )

        v=${dir//\// } # replace / by <space> in path
        t=$(printf "echo %s | sed -e 's/^\(...\).*$/\../' ; " $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'
}

回答by biell

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

这就是我如何在标题栏中缩短带有完整路径的 bash 提示(从 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.

这种方法需要非常低的 CPU 开销。