Zakończenie bash dla wartości oddzielonych przecinkami

16

Chciałbym utworzyć regułę uzupełniania dla listy parametrów oddzielonych przecinkami. Np. Mam polecenie, które otrzymuje listę nazw serwerów:

myscript -s name1,name2,name3

W tej chwili udało mi się napisać następujące uzupełnienie:

_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
}

Ale ma co najmniej 2 problemy:

  1. Sugestie dotyczące bieżącej wartości zawierają wszystkie poprzednie wartości w swoich przedrostkach.
  2. Nie uwzględnia zduplikowanych wartości.

Jakie są najlepsze praktyki w takich przypadkach? Może bash-complete ma jakieś funkcje w pakiecie dla list csv?

diffycat
źródło
3
Pomocne może być podzielenie wartości oddzielonych przecinkami na listę iterowalną, taką jak ta: IFS=, LIST=("$VARIABLE")gdzie $ VARIABLE zawiera wartości oddzielone przecinkami.
Michael Ehrenreich,
2
Fajny pomysł @MichaelEhrenreich, ale nie wolno ci cytować $VARIABLE, w przeciwnym razie nie dojdzie do dzielenia słów. po prostu użyj IFS=, LIST=($VARIABLE).
Guss

Odpowiedzi:

6

Zasadniczo nie ma sposobu, aby rozwiązać opisywane problemy, ponieważ bash używa wartości COMPREPLYbezpośrednio na wyświetlaczu, a następnie zamienia tekst użytkownika - podczas gdy aby uzyskać to, czego chcesz, musisz najpierw wygenerować możliwe uzupełnienia (tylko dodatkowe nazwy serwerów bez prefiksu), aby wyświetlić bash, a gdy bash zamierza zastąpić tekst użytkownika najdłuższym nie powodującym konfliktu łańcuchem, konieczne będzie ponowne wywołanie skryptu w celu wygenerowania tekstu z prefiksem - i bash nie ma na to możliwości.

Najlepsze, co mogłem wymyślić, to COMPREPLYwygenerować tylko pierwsze słowo z całym prefiksem ( COMPREPLY=( "${prefix},"$(compgen -W "${servers[@]}" -- ${realcur}) )), aby jeśli było tylko jedno możliwe uzupełnienie, kończy się ono automatycznie, a jeśli jest więcej niż jedno możliwe uzupełnienie , wtedy bash nie usunie tego, co zostało wpisane do tej pory (ponieważ pierwsze słowo COMPREPLYma cały prefiks, a zatem pasuje do aktualnie wpisanego tekstu i zostanie wybrane przez bash, aby zastąpić tekst użytkownika) i wyświetli opcje bez prefiksu - z wyjątkiem dla tego jednego słowa, które już zawiera prefiks, więc wynik będzie wyglądał następująco:

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

„jabłko” posortowane jako ostatnie w opcjach uzupełniania, ponieważ zawiera przedrostek zaczynający się na „b” - bardzo mylące. Więc nie polecam tego robić.

Jeśli chodzi o duplikaty - aby nie pokazywać duplikatów, wystarczy włamać się $prefixdo jego części (łatwe IFS="," prefix_parts=($prefix):), a następnie iterować nad nimi i pozostawić tylko w $serversnazwach, które nie są jeszcze wymienione. To żmudne pisanie, więc nie pokażę go tutaj, ale stosunkowo trywialne, więc jestem pewien, że dasz radę :-).

Podsumowując, nie sądzę, że powinieneś używać wartości oddzielonych przecinkami dla opcji wprowadzania, przynajmniej jeśli oczekujesz, że bash pomoże ci w zakończeniu.

Możesz obsługiwać format opcji podobny do tego: command -s <server> [<server> [..]]a następnie w celu uzupełnienia wpisów innych niż ten bezpośrednio po -sopcji, po prostu zeskanuj z powrotem $COMP_WORDStablicę od, $COMP_CWORDaż znajdziesz opcję (pasujący łańcuch -*), a jeśli jej „-s” to musisz uzupełnić nazwę serwera.

Guss
źródło