zsh действительно поддерживает «динамические хеши каталогов», они называются динамическими именованными каталогами (подробнее см. zshexpn(1)
). Имя динамического каталога указывается в квадратных скобках без кавычек: ~[name]
.
Они настраиваются путем определения функции zsh_directory_name
или путем создания массива с именем zsh_directory_name_functions
содержащего имена функций. Эти функции используются тремя способами, которые определяются первым параметром:
- проверка, является ли текущий каталог именованным каталогом (
d
)
- сопоставить имя с каталогом (
n
)
- предоставить список имен для завершения (
c
)
Не каждый режим должен быть реализован, но должен возвращать ненулевой статус.
Вот пример, который динамически называет любое /very/long/name/$USER/even/more
с помощью ~[magic:$USER]
(на основе примера из zshexpn(1)
)
zsh_directory_name() {
emulate -L zsh
setopt extendedglob
local -a match mbegin mend
local pp1=/very/long/name
local pp2=even/more
if [[ $1 = d ]]; then
if [[ $2 = (#b)($pp1/)([^/]##)(/$pp2)* ]]; then
typeset -ga reply
reply=(magic:$match[2] $(( ${#match[1]} + ${#match[2]} + ${#match[3]} )) )
else
return 1
fi
elif [[ $1 = n ]]; then
[[ $2 != (#b)magic:(?*) ]] && return 1
typeset -ga reply
reply=($pp1/$match[1]/$pp2)
elif [[ $1 = c ]]; then
local expl
local -a dirs
dirs=($pp1/*/$pp2)
for (( i=1; i<=$#dirs; i++ )); do
dirs[$i]=magic:${${dirs[$i]#$pp1/}%/$pp2}
done
_wanted dynamic-dirs expl 'user specific directory' compadd -S\] -a dirs
return
else
return 1
fi
return 0
}
Использование:
% ls /very/long/name
bar baz foo
% ls -d /very/long/name/*/even/more
/very/long/name/bar/even/more /very/long/name/foo/even/more
% cd ~[magic:foo]
% pwd
/very/long/name/foo/even/more
% cd ~[mag #TAB
user specific directory:
magic:bar magic:foo
% cd ~[magic:baz]
cd: no such file or directory: /very/long/name/baz/even/more
Каталог /very/long/name/baz
не содержит подкаталога even/more
и поэтому не имеет имени.