Я хотел бы создать правило завершения для списка параметров, разделенных запятыми. Например, у меня есть команда, которая получает список имен серверов:
myscript -s name1,name2,name3
На данный момент мне удалось написать следующее завершение:
_myscript () {
local cur prev opts
_get_comp_words_by_ref cur prev
opts='-s'
servers='name1 name2 name3'
if [[ ${cur} == -* ]] ; then
COMPREPLY=( $(compgen -W "${opts}" -- ${cur}) )
else
case "${prev}" in
-s)
if [[ "$cur" == *,* ]]; then
local realcur prefix
realcur=${cur##*,}
prefix=${cur%,*}
COMPREPLY=( $(compgen -W "${servers}" -P "${prefix}," -- ${realcur}) )
else
COMPREPLY=( $(compgen -W "${servers}" -- ${cur}) )
fi
;;
*)
# do nothing
;;
esac
fi
}
Но у него есть как минимум 2 проблемы:
- Предложения по текущему значению включают все предыдущие значения в их префиксе.
- Он не учитывает повторяющиеся значения.
Каковы лучшие практики для таких случаев? Может быть, в bash-дополнениях есть несколько связанных функций для csv-списков?
bash
autocomplete
diffycat
источник
источник
IFS=, LIST=("$VARIABLE")
где $ VARIABLE содержит значения, разделенные запятыми.$VARIABLE
, иначе разрыва слов не произойдет. просто используйтеIFS=, LIST=($VARIABLE)
.Ответы:
По сути, нет способа исправить проблемы, которые вы описываете, потому что bash использует значения
COMPREPLY
непосредственно на дисплее, а затем заменяет текст пользователя - в то время как для получения того, что вы хотите, вам нужно сначала сгенерировать возможные дополнения (только дополнительные имена серверов, без префикса) для отображения bash, затем, когда bash собирается заменить пользовательский текст самой длинной неконфликтующей строкой, вам потребуется, чтобы он снова вызвал ваш скрипт для генерации текста с префиксом - и bash не имеет возможности для этого.Лучшее, что я мог бы придумать, - это
COMPREPLY
генерировать только первое слово, имеющее весь префикс (COMPREPLY=( "${prefix},"$(compgen -W "${servers[@]}" -- ${realcur}) )
), так что, если есть только одно возможное завершение, оно завершается автоматически правильно, в то время как при наличии более одного возможного завершения , тогда bash не удалит то, что было набрано до сих пор (поскольку первое слово вCOMPREPLY
имеет полный префикс и, следовательно, соответствует набранному в настоящее время тексту, и будет выбрано bash для замены текста пользователя), и отобразит параметры без префикса - кроме для этого одного слова, которое уже содержит префикс, поэтому вывод будет выглядеть так:«Яблоко», как отсортировано последним в опциях завершения, потому что оно содержит префикс, который начинается с «b» - очень запутанно. Поэтому я не рекомендую это делать.
Что касается дубликатов - чтобы не отображать дубликаты, вам просто нужно разбить
$prefix
его на части (easyIFS="," prefix_parts=($prefix)
:), а затем перебрать их и оставить только в$servers
именах, которые еще не перечислены. Его набирать утомительно, поэтому я не буду показывать это здесь, но относительно тривиально, так что я уверен, что вы можете справиться :-).Подводя итог, я не думаю, что вы должны использовать разделенные запятыми значения для параметров ввода, по крайней мере, если вы ожидаете, что bash поможет вам с завершением.
Вы можете поддерживать формат параметров, подобный следующему:
command -s <server> [<server> [..]]
и затем для завершения записей, отличных от той, которая находится сразу после-s
параметра, просто сканируйте$COMP_WORDS
массив обратно,$COMP_CWORD
пока не найдете параметр (совпадающая строка-*
), и если его «-s» затем вам нужно сделать завершение имени сервера.источник