如何打破完整的三部曲模式

时间:2013-04-28 00:50:58

标签: bash bash-completion

我有一个命令行工具,它以三部分形式接受参数:

$ 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

当然,我对第三部分也有同样的问题。

  1. 我怎样才能让Bash逐一完成当前的单词?
  2. 如果选择了某个选项,我怎样才能让Bash不附加分隔符?
  3. 这类似于another Bash complete question,但我不想列出值的每个可能的排列,并且它们没有被格式化为文件名(不确定文件名模式是否有所不同)。

    感谢您的帮助!
    留学美国相关考试

1 个答案:

答案 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

我对自动填充并不熟悉,这是我第一次使用compgencomplete,因此我不确定我是否可以回答有关该事物理论的问题。我可以告诉你我做了什么,以防它帮助你理解这些记录错误的函数是如何工作的。 首先,我试着了解你的情况。我成功地复制了你的问题。然后我有了这个想法,即使你不想在代码中自己列出每个排列,我也可以使用局部变量来模仿它。我做的第一件事就是在我们得到第一个下划线之后得到“第一个”元素,然后将第二个元素添加到它,并将其提供给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中并且它有效。这只是我所做的总结...但我得到了一个工作版本,所以我很高兴。 : - )