オートコンプリートでスクリプトを作成する方法は?


120

のようなプログラムを使用しsvn、Gnomeターミナルで入力すると:

svn upd

ヒットするTabと自動補完されます:

svn update

私のカスタムbashスクリプトでそのようなことをすることは可能ですか?


「bash script」の説明、つまりスクリプトを編集するときですか?あなたはそれで何をしたいですか?
ブルーノペレイラ

3
コンソールでスクリプトを使用する場合
-UAdapter

修了証を記入する場所については、この質問と承認された回答のコメントを参照してください。
ジャーノ

回答:


44

Programmable Completionを使用できます。見てい/etc/bash_completionおよび/etc/bash_completion.d/*いくつかの例のために。


131
質問に直接関係する簡単な例を含めるとどうですか?
MountainX

2
Ubuntuの16の実際のスクリプトは次の場所にあります/usr/share/bash-completion/completions/<program>
ピーター

17
Imo、例はリンクではなく答えに含まれるべきです。
ビリーノア

2
このプラットフォームは、単純なGoogle検索で見つけることができる完全なドキュメントのより実用的な代替手段であると考えられます。ドキュメントのリンクをダンプしてもそれは役に立ちません。アンカーを含むリンクは確かに大きな違いはありません。
ティムシン

4
The provided link has that already-それは今日かもしれませんが、明日ではないかもしれません。または来年。または10年で。まだ関連性のあるドキュメントについて何を提案しても、Stack Overflowはこれらの理由からリンクのみの回答を推奨しません。
リアムドーソン

205

私は6ヶ月遅れていますが、同じものを探していて、これを見つけました:

新しいファイルを作成する必要があります。

/etc/bash_completion.d/foo

静的オートコンプリート(たとえば、--help/ --verbose)の場合、これを追加します:

_foo() 
{
    local cur prev opts
    COMPREPLY=()
    cur="${COMP_WORDS[COMP_CWORD]}"
    prev="${COMP_WORDS[COMP_CWORD-1]}"
    opts="--help --verbose --version"

    if [[ ${cur} == -* ]] ; then
        COMPREPLY=( $(compgen -W "${opts}" -- ${cur}) )
        return 0
    fi
}
complete -F _foo foo
  • COMP_WORDS は、現在のコマンドラインの個々の単語すべてを含む配列です。
  • COMP_CWORD 現在のカーソル位置を含む単語のインデックスです。
  • COMPREPLY Bashが可能な補完を読み取る配列変数です。

そして、compgenコマンドからの要素の配列を返し--help--verboseそして--version現在の単語に一致します"${cur}"

compgen -W "--help --verbose --version" -- "<userinput>"

ソース:http : //www.debian-administration.org/articles/316


27
これは受け入れられた答えであるはずです!これは完全な例です。
ビクターシュレーダー2015

5
ヒント:誰かが-ターゲット単語の入力を開始せずに、単語で始まっていない単語の候補を表示し、それらを表示したい場合はif [...] thenfi行と行を削除するだけです。
セドリックライヘンバッハ

1
これは私が何時間も探していた正確な答えであり、ファイルがに配置されることを決して言及していない複雑なドキュメントにdrれていることがわかります/etc/bash_completion.d/。どこかに答えを投稿したかったのでここに来ただけですが、誰かがずっと3年先にいたことがわかりました:)明確で簡潔で完全な例、ありがとう!
スティーンシュット16


34

bashの完了はすべてに保存され/etc/bash_completion.d/ます。したがって、bash_completionを使用してソフトウェアを構築している場合、deb / make installにそのディレクトリ内のソフトウェアの名前のファイルをドロップさせることは価値があります。Rsyncのbash完了スクリプトの例を次に示します。

# bash completion for rsync

have rsync &&
_rsync()
{
    # TODO: _split_longopt

    local cur prev shell i userhost path   

    COMPREPLY=()
    cur=`_get_cword`
    prev=${COMP_WORDS[COMP_CWORD-1]}

    _expand || return 0

    case "$prev" in
    --@(config|password-file|include-from|exclude-from))
        _filedir
        return 0
        ;;
    -@(T|-temp-dir|-compare-dest))
        _filedir -d
        return 0
        ;;
    -@(e|-rsh))
        COMPREPLY=( $( compgen -W 'rsh ssh' -- "$cur" ) )
        return 0
        ;;
    esac

    case "$cur" in
    -*)
        COMPREPLY=( $( compgen -W '-v -q  -c -a -r -R -b -u -l -L -H \
            -p -o -g -D -t -S -n -W -x -B -e -C -I -T -P \
            -z -h -4 -6 --verbose --quiet --checksum \
            --archive --recursive --relative --backup \
            --backup-dir --suffix= --update --links \
            --copy-links --copy-unsafe-links --safe-links \
            --hard-links --perms --owner --group --devices\
            --times --sparse --dry-run --whole-file \
            --no-whole-file --one-file-system \
            --block-size= --rsh= --rsync-path= \
            --cvs-exclude --existing --ignore-existing \
            --delete --delete-excluded --delete-after \
            --ignore-errors --max-delete= --partial \
            --force --numeric-ids --timeout= \
            --ignore-times --size-only --modify-window= \
            --temp-dir= --compare-dest= --compress \
            --exclude= --exclude-from= --include= \
            --include-from= --version --daemon --no-detach\
            --address= --config= --port= --blocking-io \
            --no-blocking-io --stats --progress \
            --log-format= --password-file= --bwlimit= \
            --write-batch= --read-batch= --help' -- "$cur" ))
        ;;
    *:*)
        # find which remote shell is used
        shell=ssh
        for (( i=1; i < COMP_CWORD; i++ )); do
            if [[ "${COMP_WORDS[i]}" == -@(e|-rsh) ]]; then
                shell=${COMP_WORDS[i+1]}
                break
            fi
        done
        if [[ "$shell" == ssh ]]; then
            # remove backslash escape from :
            cur=${cur/\\:/:}
            userhost=${cur%%?(\\):*}
            path=${cur#*:}
            # unescape spaces
            path=${path//\\\\\\\\ / }
            if [ -z "$path" ]; then
                # default to home dir of specified
                # user on remote host
                path=$(ssh -o 'Batchmode yes' $userhost pwd 2>/dev/null)
            fi
            # escape spaces; remove executables, aliases, pipes
            # and sockets; add space at end of file names
            COMPREPLY=( $( ssh -o 'Batchmode yes' $userhost \
                command ls -aF1d "$path*" 2>/dev/null | \
                sed -e 's/ /\\\\\\\ /g' -e 's/[*@|=]$//g' \
                -e 's/[^\/]$/& /g' ) )
        fi
        ;;
    *)  
        _known_hosts_real -c -a "$cur"
        _filedir
        ;;
    esac

    return 0
} &&
complete -F _rsync $nospace $filenames rsync

# Local variables:
# mode: shell-script
# sh-basic-offset: 4
# sh-indent-comment: t
# indent-tabs-mode: nil
# End:
# ex: ts=4 sw=4 et filetype=sh

プログラムに最も近いbash完了ファイルの1つを確認する価値があります。最も単純な例の1つはrrdtoolファイルです。


2
他の場所から読み込むように補完を構成できますか?IE。〜/ .localの
クリス・

1
はい、好きな場所にこのようなファイルを置いてから、次のファイルを入れることができsource ~/.local/mycrazycompletionます~/.bashrc
Stefano Palazzo


現在、ほとんどの補完はコマンドpkg-config --variable = completionsdir bash-completion`で指定されたディレクトリにあり、そのディレクトリは上記リンクのBash Completion FAQで推奨されています。
ジャルノ

34

これが完全なチュートリアルです。

オートコンプリートを機能させたいadmin.shというスクリプトの例を見てみましょう。

#!/bin/bash

while [ $# -gt 0 ]; do
  arg=$1
  case $arg in
    option_1)
     # do_option_1
    ;;
    option_2)
     # do_option_1
    ;;
    shortlist)
      echo option_1 option_2 shortlist
    ;;
    *)
     echo Wrong option
    ;;
  esac
  shift
done

オプションの候補リストに注意してください。このオプションを使用してスクリプトを呼び出すと、このスクリプトで使用可能なすべてのオプションが出力されます。

そして、ここにオートコンプリートスクリプトがあります:

_script()
{
  _script_commands=$(/path/to/your/script.sh shortlist)

  local cur
  COMPREPLY=()
  cur="${COMP_WORDS[COMP_CWORD]}"
  COMPREPLY=( $(compgen -W "${_script_commands}" -- ${cur}) )

  return 0
}
complete -o nospace -F _script ./admin.sh

完了する最後の引数は、オートコンプリートを追加するスクリプトの名前です。必要なのは、オートコンプリートスクリプトをbashrcに追加することだけです

source /path/to/your/autocomplete.sh

または/etc/bash.completion.dにコピーします


1
prev変数の目的は何ですか?あなたはそれを使用していないようです。
dimo414

@ dimo414そうそう、私はその変数を削除しました
ココシング

-o nospaceオプションは何をしますか?
アンドリューラマーラ

11

必要なのが単純な単語ベースのオートコンプリートだけである場合(したがって、サブコマンドの完了などはありません)、completeコマンドには-W正しいことを行うオプションがあります。

たとえば、jupyter.bashrcというプログラムをオートコンプリートするために、次の行があります。

# gleaned from `jupyter --help`
_jupyter_options='console qtconsole notebook' # shortened for this answer
complete -W "${_jupyter_options}" 'jupyter'

jupyter <TAB> <TAB>私のためにオートコンプリート。

gnu.org のドキュメントは役に立ちます。

IFS変数が正しく設定されていることに依存しているように見えますが、それは私にとって問題を引き起こしていません。

ファイル名補完とデフォルトのBASH補完を追加するには、次の-oオプションを使用します。

complete -W "${_jupyter_options}" -o bashdefault -o default 'jupyter'

zshでこれを使用するには、次のコードを追加してから、completeコマンドを実行します~/.zshrc

# make zsh emulate bash if necessary
if [[ -n "$ZSH_VERSION" ]]; then
    autoload bashcompinit
    bashcompinit
fi

これをどのように動作させるのbash jupyter <TAB><TAB>ですか?
papampi

@papampi、それは1レベルの完了でのみ機能すると思います-上記のより複雑な答えの1つが必要な2つのレイヤーでそれを行うと思います。また、最近、bashの完了に関するかなりまともなチュートリアルを読みました。それはあなたが必要とするものを正確にはしませんが、おそらくあなたを助けるでしょう。幸運を!
ベン
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.