Совпадение в любом месте имени файла довольно сложно, и я не уверен, что это действительно так полезно. Сопоставление в начале имен файлов имеет больше смысла и намного проще в реализации, даже рекурсивно.
Теперь вы упомянули find как требование, но bash (начиная с версии 4.0) также может рекурсивно находить файлы, и bash должно быть более эффективным, чтобы эта часть выполнялась. Для рекурсивного совпадения в bash вы включаете опцию оболочки globstar, выполняя shopt -s globstar
, тогда две последовательные звездочки, **
, будут совпадать рекурсивно.
Далее, учитывая, что вы хотите рекурсивно сопоставлять файлы в репозитории git, у нас есть лучший способ обнаружить, что мы на самом деле в репозитории git, в противном случае, если вы случайно запустите его, например, в /
, Ваше приглашение будет зависать в ожидании bash для поиска по всей вашей файловой системе. Следующая функция должна быть достаточно эффективной для определения, находимся ли мы в git-репозитории. Учитывая текущий рабочий каталог, например /foo/bar/baz
, он будет искать /foo/bar/baz/.git
, /foo/bar/.git
, /foo/.git
, /.git
и вернет true, если найдет, false в противном случае.
isgit() {
local p=$PWD
while [[ $p ]]; do
[[ -d $p/.git ]] && return
p=${p%/*}
done
return 1
}
Для простоты мы создадим команду gadd
для добавления дополнений. Функция завершения может быть применена только к первому слову команды. Например. мы можем добавить завершение для git
, но не git add
, поэтому мы создадим новую команду, которая превращает git add
в одно слово.
gadd() {
git add "$@"
}
Теперь для фактической функции завершения. Когда вызвано нажатием TAB, функция будет вызвана с тремя аргументами. $1
- завершаемая команда, $2
- текущее слово завершаемой командной строки, а $3
- предыдущее слово в строке. Таким образом, файлы, которые мы хотим найти, будут сопоставлены с глобусом **/"$2"*
; все файлы, начинающиеся с "$2"
. Мы повторяем эти имена файлов и добавляем их в массив COMPREPLY. Если массив COMPREPLY содержит только одно значение после выполнения функции, слово будет заменено этим значением. Если оно содержит более одного значения, нажмите вкладку в другой раз, чтобы получить список всех совпадений.
shopt -s globstar
_git_add_complete() {
local file
isgit || return
for file in **/"$2"*; do
# If the glob doesn't match, we'll get the glob itself, so make sure
# we have an existing file
[[ -e $file ]] || continue
# If it's a directory, add a trailing /
[[ -d $file ]] && file+=/
COMPREPLY+=( "$file" )
done
}
complete -F _git_add_complete gadd
Добавьте три вышеуказанных кодовых блока в ваш ~/.bashrc
, затем откройте новый терминал, войдите в репозиторий git и попробуйте gadd something<tab>
.