Как добавить шаблон для завершения bash (для распаковки)?

11

Когда я печатаю

unzip <tab>

Я получаю список всех файлов, оканчивающихся на .zip, который является стандартным поведением завершения табуляции для unzipкоманды.

Тем не менее, я также хочу завершения bash для unzipфайлов списка, которые заканчиваются .udp, в дополнение к .zipфайлам. Как я могу добиться этого поведения в моем местном .bashrc?

Alex
источник

Ответы:

22

Вместо того, чтобы продолжать комментировать ...


complete -f -X '!*.@(zip|udp)' unzip

следует добавить завершение для

-f -X '!*.@(zip|udp)'
 |  |  | |||________|
 |  |  | ||     |
 |  |  | ||     +- filterpat: zip or udp
 |  |  | |+-------------  @ : Matches one of the given patterns
 |  |  | +-------------- *. : Anything+<dot>
 |  |  +----------------  ! : Negate
 |  +------------------- -X : Filter out matches in "filterpat"
 +---------------------- -f : files

Другими словами: заполните файлы и удалите все, не оканчивающиеся на .zipили .udp.


Дополнительно

Если вы добавите -o defaultзавершение, вы завершите / сопоставите все файлы и каталоги, если нет файлов, оканчивающихся на .zipили .udp.

Если вы добавите -o plusdirsзавершение, вы добавите любые каталоги в дополнение к любым совпадениям файлов, оканчивающихся на .zipили .udp.

Текущий

При использовании complete -p unzipвы получаете текущий шаблон.

Из ваших комментариев это звучит в основном так, как будто вы пропустили +или @в шаблоне, как в:

# Err:
complete -f -X '!*.(zip|udp)' unzip
                   |
                   +---- Missing + or @

что означает совпадение с любым файлом, буквально оканчивающимся на.(zip|udp) . Например

touch 'file_test.(zip|udp)'

Также взгляните на этот раздел руководства:

это возможно, например extglob, не включен. Включить с помощью:

shopt -s extglob

Проверьте текущее состояние всех shoptнастроек, введя:

shopt

функция

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

_filedir_xspec, Как правило , является функцией Debian. У вас может быть что-то вроде этого:

$ cat /etc/bash_completion
. /usr/share/bash-completion/bash_completion

Что означает /usr/share/bash-completion/bash_completionполучить источник. Здесь вы найдете соответствующую функцию . Несколькими строками ниже вы видите, что эта функция / завершение добавляется функцией с именем _install_xspecнапример:

_install_xspec '!*.@(zip|[ejsw]ar|exe|pk3|wsz|zargo|xpi|s[tx][cdiw]|sx[gm]|o[dt][tspgfc]|od[bm]|oxt|epub|apk|do[ct][xm]|p[op]t[mx]|xl[st][xm])' unzip zipinfo

Ручные записи:


Обновление к комментариям 1:

- Нет совпадения из-за неправильных архивов или прав доступа к файлам.

Это не должно повлиять на результат. completeсопоставляет только файлы, заданные правилами, и не обрабатывает файлы. Если вы можете перечислить их с ls, они должны совпадать.

В качестве примечания можно добавить такую ​​функциональность, используя полную функцию:

function _unzip_validated() {
    # 1. Generate list of files ending in e.g. .zip and .udp
    # 2. Validate each file and remove invalid ones from file list.
}

complete -F _unzip_validated unzip

- Цвета. Почему lsотличается test.zipот test.upd?

Это не влияет complete. Цвета lsпредоставлены $LS_COLORS. Пытаться:

echo "$LS_COLORS" | tr : '\n' | sort

Вы должны увидеть что-то вроде *.zip=01;31:

*.zip=01;31
|____| |  |
   |   |  +--- Red
   |   +------ Bold
   +---------- Files with .zip extension

*.udp с другой стороны, нет записи, связанной с ним, поэтому нет окраски.


Следующий шаг (должен был быть первым)

  1. Откройте терминал и перейдите в каталог с тестовыми файлами. Оба .zip и .udp
  2. Войти bash --norc
  3. Войти complete -f -X '!*.@(zip|udp)' unzip
  4. Войти shopt -s extglob
  5. Войти unzip <tab><tab>

Результат?

Кроме того, нажмите изменить под вашим вопросом и добавьте вывод:

bind -V
shopt
env

может быть полезным

Runium
источник
Большое спасибо за ваше превосходное и длинное объяснение, но оно все равно не работает. complete -p unzipдает complete -f -X '!*.@(zip|udp)' unzipи unzip <tab>завершает файл с именем test.zip. Тем не менее, каталог также содержит файл с именем, test.updкоторый не найден при завершении вкладки unzip. Может, факт прав доступа к файлу или нулевая длина файла могут объяснить это странное поведение?
Алекс
@ Алекс: Должен получить завершение как для пустых, так и для допустимых файлов, а также для файлов, у которых нет разрешения. Это то же самое поведение, если вы добавите его в тестовый скрипт? Например, какой-нибудь тестовый скрипт с установленным исполнением:, ~/bin/testing2. complete -f -X '!*.@(zip|udp)' testing, 3. testing <tab><tab>?
Runium
@Alex: Вы также можете обновить Q с выводом shopt
Runium
extglobактивирован Пример с «test» выбирает zipфайл только снова. Я заметил, что test.zipотображается красным цветом, в то время test.updкак отображается белым цветом ls -l, оба файла пусты с одинаковыми разрешениями, владельцем смещения и связью группы. Почему lsотличается test.zipот test.upd? Может быть, это подсказка к моей проблеме?
Alex
@Alex: добавлено обновление.
Runium
3

В файле /etc/bash_completion, который вы, вероятно, где-то используете, завершение по умолчанию, по крайней мере для моей версии bash(v4.2.25):

complete -f -X '!*.@(zip|[ejw]ar|exe|pk3|wsz|zargo|xpi|sxw|o[tx]t|od[fgpst]|epub|apk)' unzip zipinfo

Попробуйте изменить все выражение на

complete -f -X '!*.@(zip|[ejw]ar|exe|pk3|wsz|zargo|xpi|sxw|o[tx]t|od[fgpst]|epub|apk|udp)' unzip zipinfo

И добавить в свой .bash_profile

BSD
источник
Это не решает мою проблему. Если я так и сделаю исходный код, то unzip <tab>не найдет .zipни .updфайлов, ни других файлов.
Алекс
Попробуйте дважды нажать на вкладку , посмотрите, если это не так. Работают ли другие дополнения как ожидалось? Например gzipс .gzфайлами?
BSD
Двойной удар по вкладке ничего не меняет. Использование gunzipс .gzфайлами выберите только те файлы , оканчивающиеся на .gz, но это определение также различны: complete -F _filedir_xspec gunzip.
Алекс
Вы источник файла /etc/bash_completionв вашем .bashrc?
BSD
Попробуйтеshopt -s extglob
Эдвард Фальк
2

Попробуйте добавить эту строку в ваш .bashrc:

complete -f -o default -X '!*.+(zip|udp)' unzip
MKC
источник
Кажется, с этим предложением я найду .udpфайлы, но только если нет .zipфайлов. Если a test.zipи test.udpfile присутствуют в текущем каталоге, unzip <tab>перечисляются только .zipфайлы. Я ожидаю увидеть оба файла (то есть завершение bash даст test.).
Алекс
Вы уверены? Я проверил мой Bash, и я, кажется, найти оба udpи zipфайлы. Вы источник .bashrcпосле добавления строки?
MKC
Я повторил в новом терминале, и теперь unzip <tab>список всех файлов, даже те, которые заканчиваются в другой фразе. Теперь именно то, что мне нужно.
Алекс
Странно .. Я использую GNU bash версии 4.2.25 и работает как положено. На какой версии Bash вы работаете?
MKC
Не могли бы вы попытаться добавить две отдельные строки: complete -f -o default -X '!*.zip' unzipиcomplete -f -o default -X '!*.udp' unzip
MKC
1

Лучше использовать _filedirвместо «сырых» complete.

обоснование

  • grep _filedir -r $(pkg-config --variable=completionsdir bash-completion) | wc -l
  • пути tilde ( ~) расширяются
  • Префиксы удаляются для каталогов, т. Е. Для /home/tux/Do<TAB><TAB>списка, который вы получаете в качестве ответа, удаляется «/ home / tux» и, следовательно, он намного более компактен
  • Проще внедрить и повысить безопасность

MWE

_unzip_completor()
{
    # init bash-completion's stuff
    _init_completion || return

    # fill COMPREPLY using bash-completion's routine
    _filedir '@(zip|udp)'
}
complete -F _unzip_completor unzip
Johannes
источник