我有一个命令行工具,它以三部分形式接受参数:
$ t first_second_third
我有first
的一组有效值,second
的一组有效值,以及third
的一组有效值。我想使用Bash完整功能来完成选项值的每个部分,如下例所示:
$ t [tab][tab] # shows options for first part
walk run skip bike
$ t w[tab] # completes first part and appends delimiter
$ t walk_[tab][tab] # shows options for second part
home work park
$ t walk_h[tab] # completes second part and appends delimiter
$ t walk_home_[tab][tab] # shows options for second part
morning afternoon evening
$ t walk_home_a[tab] # completes second part and appends space
$ t walk_home_afternoon
我有这段代码:
_tool () {
local cur="${COMP_WORDS[COMP_CWORD]}"
local first="walk run skip bike"
local second="home work park"
local third="morning afternoon evening"
case "${cur}" in
*_*_*)
COMPREPLY=( $(compgen -W "${third}" -- "") ); return 0;;
*_*)
COMPREPLY=( $(compgen -W "${second}" -S "_" -- ${cur}) ); compopt -o nospace; return 0;;
*)
COMPREPLY=( $(compgen -W "${first}" -S "_" -- ${cur}) ); compopt -o nospace; return 0;;
esac
}
complete -F _tool t
第一个条款很有效;没什么特别的。但第二个条款没有给我任何选择或完成。
$ t [tab][tab]
bike_ run_ skip_ walk_
$ t b[tab]
$ t bike_[tab][tab] # nothing but bells
我用以下内容替换了第二个子句(即我在${cur}
调用中用空字符串替换了COMPREPLY
):
COMPREPLY=( $(compgen -W "${second}" -S "_" -- "") ); compopt -o nospace; return 0;;
我在命令行上获得了所有选项的列表,但没有完成。
$ t bike_[tab][tab]
home_ park_ work_
$ t bike_h[tab][tab]
home_ park_ work_
$ t bike_ho[tab][tab]
home_ park_ work_
我认为可能与${cur}
和COMPREPLY
单词列表存在一些不良的交互,所以我再次更改了第二个子句,添加了与当前单词的第一部分匹配的前缀:
local prefix=( $(expr "${cur}" : '\(.*_\)') )
COMPREPLY=( $(compgen -W "${second}" -P "${prefix}" -S "_" -- "") ); compopt -o nospace; return 0;;
这没什么用。 ${cur}
命令仍在COMPREPLY
时,我再也没有选项或完成。换了一个空字符串,我得到了完整的选项(不仅仅是当前的部分)。但是,按Tab键会删除键入的内容。
$ t bike_[tab][tab]
bike_home_ bike_park_ bike_work_
$ t bike_ho[tab]
$ t bike_ # "ho" was erased
当然,我对第三部分也有同样的问题。
这类似于another Bash complete question,但我不想列出值的每个可能的排列,并且它们没有被格式化为文件名(不确定文件名模式是否有所不同)。
感谢您的帮助!
留学美国相关考试
答案 0 :(得分:4)
我能够创造你想要的东西。请参阅下面的代码:
_tool () {
local cur="${COMP_WORDS[COMP_CWORD]}"
local first="walk run skip bike"
case "${cur}" in
*_*_*)
local firstsecond=`echo ${cur} | awk -F '_' '{print $1"_"$2}'`
local third="${firstsecond}_morning ${firstsecond}_afternoon ${firstsecond}_evening"
COMPREPLY=( $(compgen -W "${third}" -- ${cur}) ); return 0;;
*_*)
local firstcomp=`echo ${cur} | awk -F '_' '{print $1}'`
local second="${firstcomp}_home ${firstcomp}_work ${firstcomp}_park"
COMPREPLY=( $(compgen -W "${second}" -S "_" -- ${cur}) ); compopt -o nospace; return 0;;
*)
COMPREPLY=( $(compgen -W "${first}" -S "_" -- ${cur}) ); compopt -o nospace; return 0;;
esac
}
complete -F _tool t
我对自动填充并不熟悉,这是我第一次使用compgen
或complete
,因此我不确定我是否可以回答有关该事物理论的问题。我可以告诉你我做了什么,以防它帮助你理解这些记录错误的函数是如何工作的。
首先,我试着了解你的情况。我成功地复制了你的问题。然后我有了这个想法,即使你不想在代码中自己列出每个排列,我也可以使用局部变量来模仿它。我做的第一件事就是在我们得到第一个下划线之后得到“第一个”元素,然后将第二个元素添加到它,并将其提供给compgen。令我惊讶的是,它运作良好。然后我尝试对第3级做同样的事情......然后问题开始了。我发现第二部分的效果并不像我想象的那么好。完成第一个单词后,我会得到第二个单词的建议;在选择一个单词作为第二个单词并点击[TAB]之后,第一个下划线将消失。
$ t [tab][tab] # shows options for first part
bike_ run_ skip_ walk_
$ t w[tab] # completes first part and appends delimiter
$ t walk_[tab][tab] # shows options for second part
walk_home_ walk_park_ walk_work_
$ t walk_h[tab] # completes second part and appends delimiter
$ t walk_home_[tab][tab] # screws up with it
$ t walkhome_
我尝试将下划线移动到awk,但没有成功:
local first=`echo ${cur} | awk -F '_' '{print $1"_"}'`
local second="${first}home ${first}work ${first}park"
出于某种原因,我不得不将变量名称更改为与“first”不同的名称,并且它开始工作。然后,在第3个元素上我遇到了你上次描述的同样的问题,我在第3个元素中输入的内容会消失,但[tab] [tab]会给我选项:
$ t walk_home_[tab][tab] # shows options for second part
morning afternoon evening
$ t walk_home_aft[tab] # erases what I typed
$ t walk_home_
我在第3个单词中将${cur}
添加到compgen中并且它有效。这只是我所做的总结...但我得到了一个工作版本,所以我很高兴。 : - )