我实现了一个提示路径缩短器,用于将bash包含在PS1环境变量中,这会将工作目录缩短为更紧凑但仍具有描述性的内容。我很好奇其他想法可能存在。
这是挑战:
创建一个bash函数_dir_chomp
,它可以像这样包含在PS1中(插入换行符以便于阅读):
PS1='\[\033[01;32m\]\u@\h\[\033[01;34m\] $(
_dir_chomp "$(pwd)" 20
)\[\033[01;37m\]$(parse_git_branch)\[\033[01;34m\] \$\[\033[00m\] '
以“20”为最大长度的参数作为软限制。以下是这些例子:
/usr/portage/media-plugins/banshee-community-extensions/files
变为/u/p/m/b/files
/home/user1/media/video/music/live-sets
变为~/m/v/m/live-sets
(请注意〜字符作为$ HOME的替代品)/home/user2/media
不会更改(不超过20个字符限制)/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
(最后一个组件保持未被缩短:软限制)/home/user1/src
变为~/src
($ HOME总是缩短)/home/user1/.kde4/share/config/kresources
变为~/.k/s/c/kresources
(请注意保留前缀点)当前用户是user1。
允许调用外部解释器,如awk
,perl
,ruby
,python
,但不能编译C程序或类似程序。换句话说:不允许使用外部源文件,代码必须是内联的。最短版本获胜。 bash函数体的长度(和称为子函数)计数,意味着:
_sub_helper() {
# this counts
}
_dir_chomp() {
# these characters count (between { and })
_sub_helper "foobar" # _sub_helper body counts, too
}
答案 0 :(得分:12)
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[*]}"
}
出于测试目的,我假设问题意味着当前用户是“user1”。
注意:Bash 4有一个变量PROMPT_DIRTRIM
,通过根据其值保留子目录的数量并用{{1替换其余的目录来缩短\w
中的PS1
转义。 }}
...
答案 1 :(得分:8)
这个字符比我的其他答案短20个左右:
_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
}
答案 2 :(得分:1)
当我有了这个挑战的想法时,这是我自己的解决方案。灵感实际上来自Jolexa's Blog。
所以在这里,可执行形式的ruby实现:
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
bash函数中的实际单行实现:
_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'
}
答案 3 :(得分:0)
仅有bash内部构件,不使用sed的另一种解决方案
shortpath()
{
dir=${1%/*} && last=${1##*/}
res=$(for i in ${dir//\// } ; do echo -n "${i:0:3}../" ; done)
echo "/$res$last"
}
我以前的解决方案,包括bash和sed。 它将3个第一个角色中的每个目录切开并添加“ ..”,如下所示: / 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'
}
答案 4 :(得分:-1)
这是我用标题栏中的/ full路径缩短我的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} \$ '
此方法需要非常低的CPU开销。