Я реализовал быстрое сокращение пути для включения 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-is-очень-long-path-name-with-than-20-chars
становится ~ / this-is-is-очень-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
, но не скомпилированные программы на Си или аналогичные. Другими словами: внешние исходные файлы не допускаются, код должен быть встроенным. Кратчайшая версия выигрывает. Длина тела функции bash (и вызываемых подфункций) означает:
_sub_helper() {
# this counts
}
_dir_chomp() {
# these characters count (between { and })
_sub_helper "foobar" # _sub_helper body counts, too
}
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
, которая сокращает escape-последовательность \ w
в PS1
, сохраняя количество подкаталогов в соответствии с ее значением и заменив остальные на ...
/$ PROMPT_DIRTRIM=2
/$ echo $PS1
\w\$
/$ pwd
/
/$ cd /usr/share/doc/bash
.../doc/bash$
Этот ответ примерно на 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
}
Это было мое собственное решение, когда у меня возникла идея для этой задачи. Вдохновением послужил Блог Джолексы.
Итак, вот она, реализация на рубине в удобочитаемой форме:
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'
}