Задача кода: Bash приглашение на короткий путь
Я применил кратчайший путь для bash, который будет включен в переменную среды PS1, что сокращает рабочий каталог до более компактного, но все же описательного. Мне любопытно, какие существуют другие идеи.
Здесь проблема:
Создайте функцию bash _dir_chomp
, которая может быть включена в PS1, как это (разрывы строк вставлены для удобочитаемости):
PS1='\[\033[01;32m\]\[email protected]\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 char не превышено)
-
/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
}
Ответы
Ответ 1
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
, которая сокращает \w
escape в PS1
, сохраняя количество подкаталогов в соответствии со своим значением и заменяя остальные на ...
/$ PROMPT_DIRTRIM=2
/$ echo $PS1
\w\$
/$ pwd
/
/$ cd /usr/share/doc/bash
.../doc/bash$
Ответ 2
Это примерно 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
}
Ответ 3
Это было мое собственное решение, когда у меня возникла идея этой проблемы. Вдохновение действительно произошло от Jolexa 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'
}
Ответ 4
Другое решение с использованием только внутренних компонентов 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'
}
Ответ 5
Вот как я сокращаю свой bash запрос w/полный путь в заголовке (работает с 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} \$ '
Этот метод требует очень низких затрат на процессор.