web-dev-qa-db-ja.com

カンマ区切り値のbash補完

カンマ区切りのパラメータリストの補完ルールを作成したいのですが。例えば。サーバー名のリストを受け取るコマンドがあります:

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
}

しかし、少なくとも2つの問題があります。

  1. 現在の値の提案には、プレフィックスに以前のすべての値が含まれます。
  2. 重複する値は考慮されません。

そのような場合のベストプラクティスは何ですか?たぶんbash-completionsにはcsvリスト用のバンドルされた関数がいくつかありますか?

17
diffycat

Bashはディスプレイで直接COMPREPLYの値を使用し、次にユーザーのテキストを置き換えるため、基本的に説明した問題を修正する方法はありません。必要なものを取得するには、最初に生成する必要があります。 bashが表示する可能性のある補完(プレフィックスなしの追加のサーバー名のみ)。bashがユーザーテキストを競合しない最長の文字列に置き換えようとしているときに、スクリプトを再度呼び出してテキストを生成する必要があります。接頭辞が-で、bashにはそのための機能がありません。

私が思いつくことができる最善の方法は、接頭辞全体(COMPREPLY=( "${prefix},"$(compgen -W "${servers[@]}" -- ${realcur}) ))を持つ最初の単語のみを使用してCOMPREPLYを生成することです。これにより、可能な補完が1つしかない場合は、自動的に正しく完了しますが、可能な完了が複数ある場合、bashはこれまでに入力されたものを削除しません(COMPREPLYの最初の単語にはプレフィックス全体が含まれているため、現在入力されているテキストと一致し、ユーザーのテキストを置き換えるためにbashによって選択されます)、プレフィックスなしのオプションが表示されます-すでにプレフィックスが含まれている1つの単語を除いて、出力は次のようになります。

_$ 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」の場合は、サーバー名を補完する必要があります。

6
Guss