重击以逗号分隔的值


16

我想为逗号分隔的参数列表创建完成规则。例如,我有接收服务器名称列表的命令:

myscript -s name1,name2,name3

现在,我已经完成以下工作:

_myscript () {
  local cur prev opts

  _get_comp_words_by_ref cur prev

  opts='-s'

  servers='name1 name2 name3'

  if [[ ${cur} == -* ]] ; then
    COMPREPLY=( $(compgen -W "${opts}" -- ${cur}) )
  else
    case "${prev}" in
      -s)
        if [[ "$cur" == *,* ]]; then
          local realcur prefix
          realcur=${cur##*,}
          prefix=${cur%,*}
          COMPREPLY=( $(compgen -W "${servers}" -P "${prefix}," -- ${realcur}) )
        else
          COMPREPLY=( $(compgen -W "${servers}" -- ${cur}) )
        fi
        ;;
      *)
        # do nothing
        ;;
    esac
  fi
}

但是它至少有两个问题:

  1. 对当前值的建议在其前缀中包括所有先前的值。
  2. 它不考虑重复值。

这种情况下的最佳做法是什么?也许bash-completions具有一些csv-list捆绑功能?


3
可能会有帮助的是,您可以将逗号分隔的值拆分成一个可迭代的列表,如下所示:IFS=, LIST=("$VARIABLE")其中$ VARIABLE包含逗号分隔的值。
Michael Ehrenreich

2
好主意@MichaelEhrenreich,但您不能引用$VARIABLE,否则不会发生断字的情况。只是使用IFS=, LIST=($VARIABLE)
2014年

Answers:


6

基本上没有办法解决您描述的问题,因为bash COMPREPLY直接在显示中使用值,然后替换用户的文本-在获取所需内容的同时,您首先需要生成可能的补全(只是附加的服务器名称,不带前缀)以显示bash,然后,当bash将用最长的非冲突字符串替换用户文本时,您需要它再次调用脚本以生成带有前缀的文本-和bash没有设施。

我能想到的最好的办法是COMPREPLY仅使用带有完整前缀(COMPREPLY=( "${prefix},"$(compgen -W "${servers[@]}" -- ${realcur}) ))的第一个单词来生成,这样,如果只有一个可能的完成,它将自动正确完成,而如果有多个可能的完成, ,那么bash不会删除到目前为止已键入的内容(因为其中的第一个单词COMPREPLY具有完整的前缀,因此与当前键入的文本匹配,并且将由bash选择以替换用户的文本),并且将显示不带前缀的选项-除外对于已经包含前缀的那个单词,因此输出将如下所示:

$ command -s banana,a
ananas     apricot    banana,apple

“ apple”在完成选项中排在最后,因为它带有以“ b”开头的前缀-非常混乱。因此,我不建议您这样做。

关于重复项-为了不显示重复项,您只需要$prefix分成一部分(简单IFS="," prefix_parts=($prefix):),然后遍历它们,只保留$servers尚未列出的名称。它的输入很乏味,所以在这里我不会显示它,但是相对琐碎,所以我确定您可以管理:-)。

总而言之,我不认为您应该使用逗号分隔的值作为输入选项,至少如果您希望bash可以帮助您完成输入。

您可以支持这样的选项格式:command -s <server> [<server> [..]]然后为完成除-s选项后紧跟的选项之外的其他项,只需$COMP_WORDS从数组中扫描回去,$COMP_CWORD直到找到一个选项(与匹配的字符串-*)为止,然后选择“ -s”即可您需要完成服务器名称的填写。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.