カスタム bash タブ補完は可能な補完を表示しますが、実際には入力を完了しません。

カスタム bash タブ補完は可能な補完を表示しますが、実際には入力を完了しません。

実際にここに投稿する前に、この問題を解決するために本当に一生懸命努力していましたが、この特定の問題を解決した他の人の例を見つけることができないようです。

Ubuntu 17.10を実行しています。

私のスクリプトの1つのタブの完成を処理するカスタム関数を作成しました。その目的は、スクリプト名を入力して[TAB]を押すと、「.use」で終わる/ opt / useのすべてのファイルが一覧表示されることです(「.use」または先行パスは表示されません)。私はこれまでこれを達成したようです。

/opt/use 以下のファイルは次のとおりです。

blender-2.79.use
chrome.use
clarisse-3.6.use
unity-2017.3.0p2.use

関数と完成したコードは次のとおりです。

_use () {
    files=( `compgen -f -X "!*.use" /opt/use/` )
    output=()
    for file in "${files[@]}"; do
        fileBaseName=`basename $file .use`
        output+=("$fileBaseName")
    done
    COMPREPLY=( ${output[@]} )
}
complete -F _use use

私を厳しく判断しないでください。私はプログラマーではなくグラフィックアーティストです。 :)

また、私の "use"スクリプトは実際には次のコマンドのエイリアスです。

source /opt/scripts/use.sh

次のように入力します。

use[SPACE][TAB][TAB]

/opt/use で ".use" で終わるファイルのリストを正常に取得しました。

今まではそんなに良くなった。たとえば、「use[SPACE][TAB][TAB]」と入力すると、次のようになります。

bvz@bvz-xps15-linux:~$ use 
blender-2.79      chrome            clarisse-3.6      unity-2017.3.0p2  

最初の質問は、なぜ[TAB]を2回押すのですか?最初はビープ音だけが聞こえます。第二に、私にオプションが提示されました。これは私にとって問題ではありません。これが私の問題の手がかりかどうか疑問に思います。

完全に一意にするのに十分な文字を入力すると、タブ補完機能は実際に行を「完了」しません。私が入力したとおりに正確にエントリを作成し、/ opt / useにファイルリストを再表示します。たとえば、次のように入力すると:

use clar[TAB][TAB]

読み取る行を埋める代わりに:

use clarisse-3.6

これが私が期待するもの(そして私が求めているもの)であり、行を次のように保ちます。

use clar

そして私にできることの完全なリストを見せました。例は次のとおりです。

bvz@bvz-xps15-linux:~$ use clar[TAB][TAB]
blender-2.79      chrome            clarisse-3.6      unity-2017.3.0p2  
bvz@bvz-xps15-linux:~$ use clar

可能な唯一の完了にもかかわらず、「clarisse-3.6」の行の読み取りは実際には完了しません。

誰かが私が間違っていることを教えてもらえますか?また、重複であればお詫び申し上げます。数日間周りを見回しましたが、この問題を解決することはこんにちはこの問題に直面した人の事例を見つけることができません。

ありがとう

答え1

解決策を教えてくれた村に感謝します。

明らかに、私の問題は、私の関数が呼び出されるたびに常に可能な一致の完全なリストを返すことです。ユーザーがこれまでに入力したものと一致する可能性のある完成品を返すだけです。アイテムが1つだけ返されると、bashは自動的に残りの行を完成します。

これは有効な機能です。可能な各補完を追加する前に、最初に入力した単語で補完が始まるかどうかをすばやく確認してください。私はこれに正規表現を使います。また、まだ何も入力していないことをテストする必要があります。この場合、常にすべてを返します。

また、より多くの変数を「ローカル」にするために変更しました。

_use () {
    local word="${COMP_WORDS[$COMP_CWORD]}"
    local files=( `compgen -f -X "!*.use" /opt/use/` )
    local output=()
    for file in "${files[@]}"; do
        fileBaseName=`basename $file .use`
        if [[ $fileBaseName =~ ^$word.* ]] || [ "$word" == "" ]; then
            output+=("$fileBaseName")
        fi
    done
    COMPREPLY=( ${output[@]} )
}

答え2

これでこれについて考える時間があったので、完成機能を次のように単純化できると思います。

_use () {
    local word="${COMP_WORDS[$COMP_CWORD]}"
    local IFS=$'\n'
    COMPREPLY=( $(find /opt/use/ -type f -name "$word*.use" -exec basename -as .use {} +) )
}

basename新しいバージョンがそれをサポートするのに十分であると仮定し-a、そうでない場合は次のようにします-exec basename {} .use \;

関連情報