найти автозаполнение имени файла в скрипте Bash - PullRequest
2 голосов
/ 25 января 2011

Есть функция командной строки, которую я давно хотел, и я подумал о том, как лучше всего ее реализовать, но у меня ничего нет ...

Итак, что бы я хотелкогда я начинаю набирать имя файла и нажимать на вкладку, например:

# git add Foo<tab>

Я бы хотел, чтобы он запускал find . -name "*$1*" и в основном автоматически завершал полный путь к соответствующему файлу в моей командной строке..

Что у меня пока есть:

Я знаю, что мне придется написать функцию, которая будет вызывать приложение с нужными мне параметрами, например git add.После этого ему нужно перехватить событие нажатия клавиши и выполнить поиск, упомянутый выше, и отобразить результаты, если их много, или заполнить результат, если он есть.

Что я не смог сделатьвыяснить:

Как перехватить событие клавиши табуляции внутри функции внутри функции.

Так в основном в псевдокоде:

gadd() {git add autocomplete_file_search($1)}

autocomplete_file_search(keyword) {
  if( tab-key-pressed ){
    files = find . -name "*$1*";
    if( filecount > 1 ) {
      show list;
    }
    if( files == 1 ) {
      return files
    }
  }
}

Есть идеи?

спасибо.

Ответы [ 4 ]

2 голосов
/ 19 августа 2012

Совпадение в любом месте имени файла довольно сложно, и я не уверен, что это действительно так полезно. Сопоставление в начале имен файлов имеет больше смысла и намного проще в реализации, даже рекурсивно.

Теперь вы упомянули 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>.

1 голос
/ 25 января 2011

Вы должны взглянуть на это введение в завершение bash .Вкратце, в bash есть система для настройки и расширения вкладок.Это делают и другие оболочки, и у каждого есть свой способ настройки.При использовании этой системы нет необходимости делать все самостоятельно, и добавить завершение пользовательского аргумента в команду относительно просто.

0 голосов
/ 19 августа 2012

Это работает?

$ cat .bash_completion
_foo()
{
    local files
    cur=${COMP_WORDS[COMP_CWORD]}
    local files=$(for x in `find -type f`; do echo ${x}; done)
    COMPREPLY=( $( compgen -W "${files}" -- ${cur} ) )
    return 0
}
complete -F _foo foo

$ . /etc/bash_completion
$ foo ./[tab]
0 голосов
/ 05 апреля 2011

Я написал git-number , чтобы мне никогда не приходилось нажимать клавишу табуляции при указании файлов для git.

С помощью git-number я могу использовать числа для представления имен файлов, которые я хочу обработать с помощью git.

...