Завершення Bash для значень, розділених комами


16

Я хотів би створити правило завершення для списку розділених комами списку. Наприклад, у мене є команда, яка отримує список імен серверів:

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
}

Але у неї є щонайменше дві проблеми:

  1. Пропозиції щодо поточного значення включають усі попередні значення в їх префікс.
  2. Він не враховує повторюваних значень.

Яка найкраща практика для таких випадків? Може бути, bash-доповнення має деякі функції в комплекті для csv-списків?


3
Що може допомогти, це те, що ви можете розділити значення, розділені комами, на такий список ітерабелів, як цей: IFS=, LIST=("$VARIABLE")де $ VARIABLE містить значення, розділені комами.
Michael Ehrenreich

2
Хороша ідея @MichaelEhrenreich, але ви не повинні цитувати це $VARIABLE, інакше розбиття слів не відбувається. просто використовувати IFS=, LIST=($VARIABLE).
Гасс

Відповіді:


6

В основному немає можливості виправити описані вами проблеми, оскільки bash використовує значення COMPREPLYбезпосередньо на дисплеї, а потім замінити текст користувача, хоча для отримання потрібного вам потрібно спочатку генерувати можливі доповнення (лише додаткові імена серверів, без префікса) для відображення bash, тоді, коли bash збирається замінити текст користувача найдовшою суперечливою рядком, вам знадобиться його знову зателефонувати на ваш сценарій, щоб сформувати текст з префіксом - і bash не має для цього можливості.

Найкраще, що я міг би придумати - це COMPREPLYгенерувати лише перше слово, що має весь префікс ( COMPREPLY=( "${prefix},"$(compgen -W "${servers[@]}" -- ${realcur}) )), так що, якщо є лише одне можливе завершення, воно завершується автоматично правильно, тоді як якщо є більше одного можливого завершення , тоді bash не видалить те, що було введено до цього часу (тому що перше слово в COMPREPLYмає весь префікс і, таким чином, відповідає поточному набраному тексту і буде вибрано bash для заміни тексту користувача), і відобразить параметри без префікса - крім для того одного слова, яке вже містить префікс, то вихід буде виглядати так:

$ command -s banana,a
ananas     apricot    banana,apple

"apple" як відсортований останнім у варіантах завершення, оскільки він містить префікс, який починається з "b" - дуже заплутано. Тому я не рекомендую цього робити.

Що стосується дублікатів - щоб не відображати дублікатів, вам просто потрібно прорватися $prefixдо його частини (easy IFS="," prefix_parts=($prefix):), а потім перебрати їх і залишити лише $serversті імена, які ще не вказані. Його набридливо набирати, тому я не показуватиму це тут, але відносно тривіально, тому я впевнений, що вам вдасться :-).

Підводячи підсумок, я не думаю, що ви повинні використовувати розділені комами значення для параметрів введення, принаймні, якщо ви очікуєте, що bash допоможе вам у завершенні.

Ви можете підтримати такий формат опцій, як такий: command -s <server> [<server> [..]]а потім для завершення записів, відмінних від одразу після -sпараметра, просто скануйте назад через $COMP_WORDSмасив, $COMP_CWORDпоки не знайдете параметр (рядок, який відповідає -*), і якщо його "-s", то вам потрібно виконати завершення імені сервера.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.