2012-05-09 2 views
6

Есть ли способ указать, что конкретная команда имеет чувствительность к регистру, без включения чувствительности к регистру во всем мире (по крайней мере для этой оболочки)?Установка нечувствительности к регистру для заполнения bash по командному принципу

В моем конкретном случае, у меня есть небольшое приложение, которое дает мне доступ к командной строке базы данных адресов электронной почты, так что я типа:

db get email john smith 

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

COMPREPLY=($(compgen -W "$(db --complete $COMP_CWORD "$COMP_WORDS[@]"}")" -- ${COMP_WORDS[COMP_CWORD]})) 

работает, чтобы позволить мне табулятораДль полной get и email. Однако, если я тогда набираю j<tab>, он отказывается, потому что в базе данных электронной почты он правильно заглавный. Я хотел бы получить bash, чтобы закончить это в любом случае. (Если я использую капитал J, он работает.)

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

Обратите внимание, что я работаю внутри приложения при использовании readline, это только взаимодействие с bash, которое кажется проблемой.

ответ

6

Действительно, похоже, что нет никакого способа иметь compgen делать нечувствительные к регистру сопоставление со списком слов (-W). Я вижу следующие обходные пути:

Простое решение: сначала переведите как список слов, так и входной токен на все строчные буквы. Примечание: Это только опция, если она приемлема для есть все дополнения превращаются во все строчные буквы.

complete_lower() { 

    local token=${COMP_WORDS[$COMP_CWORD]} 
    local words=$(db --complete $COMP_CWORD "${COMP_WORDS[@]}") 

    # Translate both the word list and the token to all-lowercase. 
    local wordsLower=$(printf %s "$words" | tr [:upper:] [:lower:]) 
    local tokenLower=$(printf %s "$token" | tr [:upper:] [:lower:]) 

    COMPREPLY=($(compgen -W "$wordsLower" -- "$tokenLower")) 
} 

лучше, но более сложное решение: Ролл свой собственный, регистронезависимое согласования логики:

complete_custommatch() { 

    local token=${COMP_WORDS[$COMP_CWORD]} 
    local words=$(db --complete $COMP_CWORD "${COMP_WORDS[@]}") 

    # Turn case-insensitive matching temporarily on, if necessary. 
    local nocasematchWasOff=0 
    shopt nocasematch >/dev/null || nocasematchWasOff=1 
    ((nocasematchWasOff)) && shopt -s nocasematch 

    # Loop over words in list and search for case-insensitive prefix match. 
    local w matches=() 
    for w in $words; do 
     if [[ "$w" == "$token"* ]]; then matches+=("$w"); fi 
    done 

    # Restore state of 'nocasematch' option, if necessary. 
    ((nocasematchWasOff)) && shopt -u nocasematch 

    COMPREPLY=("${matches[@]}") 
} 
+0

выше решение не кажется, не совсем правильно, поскольку это возвращает только первый матч вместо всех матчей , удаление «перерыва» должно решить это. Другая проблема заключается в том, что это не работает изящно в более старых версиях bash, которые вообще не имеют опции nocasematch. Я не знаю, что было бы лучшим решением для этого, но я использовал в своем сценарии местный SHOPT = $ (shopt -p) local IGNORE_CASE = 0 [["$ {SHOPT # * shopt -u nocasematch} "==" $ SHOPT "]] || IGNORE_CASE = 1 – Neuron

+0

Спасибо, @Neuron: Я обновил код, чтобы вернуть все совпадения. Что касается опции «nocasematch», которая недоступна (знаете ли вы, в какой версии она была введена?): Можно было бы использовать ваш тест, а затем, при отсутствии опции, применить «tr [: upper:] [: lower :] 'в теле цикла' for'. Несколько более краткий способ выполнения теста доступности доступности: «local haveNoCaseMatch = 0 \ n [[-z" $ (shopt -q nocasematch 2> & 1) "]] && hasNoCaseMatch = 1 ' – mklement0

+0

Вы должны написать, что как COMPREPLY = ("$ {matches [@]}"), иначе он будет разбивать многословные опции (например, имена файлов) – Orwellophile

Смежные вопросы