Bashスクリプトに独自のオートコンプリート機能を含めることはできますか?

Bashスクリプトに独自のオートコンプリート機能を含めることはできますか?

利用可能なリソースがたくさんあります(12サム)コマンドと引数を自動補完するbashの機能を利用する方法を説明します。しかし、これらすべてのリソースを使用するには、ユーザーにコードを追加する必要がありますか、~/.bash_profileそれとも/etc/bash_completion.d/*スクリプトと利用可能な完成機能を独自に含める方法はありますか?粗雑なもの不完全例:

~/bin/script-with-integrated-autocomplete.sh:

#!/usr/bin/env bash

function _completions {
  complete ...
}

if [ "$1" == "completions" ]; then
  _completions
  exit 0
fi

# (Whatever the script really does goes here.)
# ...
# ...

この質問の文脈で問題は、上記の例を完了するには、~/bin/script-with-integrated-autocomplete.sh completionsこのような項目を追加する必要があることです.profile

個々のbashスクリプト(ファイル)が自己完結を宣言し、bashにそれを認識させる方法はありますか?電話するとき(追加システムや環境設定がないことが望ましい)?

答え1

あなたの質問の説明で述べたように、Bashは以前の設定や現在の環境を変更せずにコマンドラインを完了できません。 Bashはファイルを表示せず、明示的に実行または取得しない限り、ファイルを解釈しようとしません。

このトピックについて私が理解したことは、これらの機能が互換性とリソースの問題のために近いうちにBashに提供される可能性が低いことです。シェルとして、さまざまなシステムで安定して実行でき、さまざまな用途に適用できる必要があります。さまざまなユーザーの好みを持ち、開発者とメンテナンス者は1人だけです1。

Bashはオートコンプリートを実装するツールを提供しますが、完成ジェネレータは外部機能として設計されているようです。実際には、既存のツールと少し作業することで、必要なものを簡単に得ることができます。

サンプルスクリプトを見ると、次のようになりますfoo

#!/bin/bash

# Setting up completion for foo. Only if the script is sourced
if [ "$0" != "$BASH_SOURCE" ]; then
    _foo() {
        local cur
        COMPREPLY=()
        cur="${COMP_WORDS[COMP_CWORD]}"
        COMPREPLY=( $(compgen -W 'bar baz' -- "$cur") )
        return 0
    }
    complete -F "_foo" "foo"
    return
fi

# The body of foo -- what it does when executed
echo foo "$*"
# ...

使用バッシュ完了foo、動的にロードされたユーザー補完が格納されているディレクトリにシンボリックリンクを追加することで、自己完結型オートコンプリートを有効にできます。

ln -s /path/to/foo ~/.local/share/bash-completion/completions/

正確なパスは異なる場合があります。 bash-completionのFAQを参照して、システムがその値を確認する方法を学ぶことができます。

bashの完了がない場合は、特定の条件を満たす場合にコマンド(対応するファイル)を提供する基本的な完了機能を定義することが1つのアプローチです。ここでは、連想配列をホワイトリストとして使用します(システム内のすべてのコマンドが盲目的にインポートされるのを防ぐため)。このコードは、.bashrcインタラクティブシェルを起動するたびに、現在の環境から取得するファイル(または同等のファイル)に追加する必要があります。

_default_completion () {
    # Do nothing when completion is invoked for an empty command
    if [ "$1" = "" ]; then
        return 1
    fi
    # Get the command path, exit with failure if it can't be found
    cmd=$(type -p "$1") || return 1
    if [ "${_compwhitelist["${cmd##*/}"]}" = y ]; then
        # Source the file corresponding to the command; on success,
        # return 124 to trigger a new autocompletion attempt
        source "$cmd" && return 124
    fi
}
complete -D -F _default_completion -o bashdefault -o default

# The list of commands with embedded completion
declare -A _compwhitelist
_compwhitelist[foo]=y

私はあなたが設定ファイルを編集する必要のないソリューションを必要としていることを知っていますが、ある程度の設定が必要であることに注意してください。いつも必須の。これらのほとんどはディストリビューション/パッケージ管理者によって行われますが、ユーザーはそれを全く理解していません。

1参考資料 バッシュホームページChet Rameyのウェブサイトにアクセスし、Bashの「A1」をクリックしてください。よくある質問

答え2

はい、できます。あなたがすべきことは、環境変数COMP_LINEが設定されていることを確認してから、利用可能なすべてのオートコンプリートオプションを単にエコーすることです。オプションごとに1行ずつ入力してスクリプトを終了します。スクリプトはシェルスクリプトである必要はありません。 Python、PHP、Golangなど何でも可能です。

擬似コード:

if COMP_LINE {
  echo "Foo"
  echo "Bar"
  Exit 0
}

//Rest of the script here

次に、シェルオートコンプリートルールにスクリプトを追加するだけです。

完了 -C /usr/bin/the_script.sh the_script.sh

「the_script.sh <tab> <tab>」と入力すると、「foo,bar」オプションが表示されます。

答え3

シェルを開いて入力すると、asdfasdf Tab自動的に完了することがわかります$CWD

これを行うために呼び出された「デフォルトの完成」を見つけてラッパーを作成すると、1つの修正がすべてのスクリプトに適用されます。

ラッパーは含まれている完成を確認し、元の完成に戻ることができます。すべてのスクリプトは提案された標準に準拠する必要があります。私はresponseCOMP_LINECOMP_WORDSenv varsが良い選択になると思います。

すでに誰かがこれを行っているようです。私は私のアイデアが画期的なものだとは思わない。

関連情報