有没有办法指定特定命令具有不区分大小写,而不全局打开不区分大小写(至少对于那个shell)?
在我的特定情况下,我有一个小应用程序,它让我可以命令行访问电子邮件地址数据库,所以我输入:
db get email john smith
然后返回John Smith的电子邮件地址。所以我设法在应用程序内部完成启用:设置
COMPREPLY=($(compgen -W "$(db --complete $COMP_CWORD "$COMP_WORDS[@]"}")" -- ${COMP_WORDS[COMP_CWORD]}))
可以让我选中get
和email
。但是,如果我然后输入j<tab>
,它就会拒绝,因为在电子邮件数据库中,它被正确地大写了。无论如何,我想得到bash来完成这个。 (如果我使用大写J
,它就有效。)
如果失败了,我可以让我的--complete
选项通过匹配输入来改变其回复的情况,我想,但理想情况下,如果可能的话,命令行将与数据库匹配。
请注意,我在使用readline时在应用内部工作,它只与bash接口似乎是一个问题。
答案 0 :(得分: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[@]}")
}
答案 1 :(得分:0)
使用 grep
完成所有工作要容易得多;然后案例保留在完成中,您不必弄乱 shopt
或类似的东西。例如:
_example_completions () {
local choices="john JAMES Jerry Erik eMIly alex Don donald donny@example.com RON"
COMPREPLY=( $( echo "$choices" | tr " " "\n" | grep -i "^$2" ) )
}
这里,$choices
是您的单词列表,tr
用于将单词之间的空格更改为换行符,以便 grep
可以理解它们(如果您的单词已经换行符分隔),-i
选项不区分大小写匹配,"^$2"
匹配当前单词(bash 将其作为 $2
传递)在行首。
$ example dO<tab>
Don donald donny@example.com