Is there a way to specify that a particular command has case insensitivity, without turning on case insensitivity globally (at least for that shell)?
In my particular case, I have a small app that gives me command line access to a database of email addresses, so I type:
db get email john smith
and it returns back with John Smith's email address. So I've managed to enable completion largely inside the app: setting
COMPREPLY=($(compgen -W "$(db --complete $COMP_CWORD "$COMP_WORDS[@]"}")" -- ${COMP_WORDS[COMP_CWORD]}))
works to allow me to tab-complete get
and email
. However, if I then type j<tab>
, it refuses, because in the email database, it's properly capitalised. I'd like to get bash to complete this anyway. (If I use a capital J
, it works.)
Failing that, I can have my --complete
option change the case of its reply by matching the input, I suppose, but ideally the command line would match the database if at all possible.
Note that I have this working inside the app when using readline, it's only interfacing with bash that seems to be an issue.
Indeed there seems to be no way to have compgen
do case-insensitive matching against the word list (-W
).
I see the following workarounds:
Simple solution: Translate both the word list and the input token to all-lowercase first. Note: This is only an option if it's acceptable to have all completions turn into all-lowercase.
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"))
}
Better, but more elaborate solution: Roll your own, case-insensitive matching logic:
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[@]}")
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With