Как создать скрипт с автозаполнением?

Когда я использую программу, подобную svn и я набираю в терминале Gnome:

svn upd

и ударил Tab он автоматически заполняется до:

svn update

Можно ли сделать что-то подобное в моем пользовательском скрипте bash?

Вам нужно будет создать новый файл:

/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>"

Источник

Вот полный учебник.

Давайте рассмотрим пример скрипта, который называется admin.sh к которому вы хотели бы, чтобы автозаполнение работало.

#!/bin/bashwhile [ $# -gt 0 ]; do  arg=$1  case $arg in    option_1)     # do_option_1    ;;    option_2)     # do_option_2    ;;    shortlist)      echo option_1 option_2 shortlist    ;;    *)     echo Wrong option    ;;  esac  shiftdone

Обратите внимание на опцию shortlist. Вызов скрипта с этой опцией выведет все возможные параметры для этого скрипта.

И вот у вас есть сценарий автозаполнения:

_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

Вы можете использовать Программируемое Завершение. Взгляните на /etc/bash_completion и /etc/bash_completion.d/* для некоторых примеров.

Все завершения bash хранятся в /etc/bash_completion.d/. Так что, если вы создаете программное обеспечение с помощью bash_completion, было бы целесообразно, чтобы deb/make install поместил файл с именем программного обеспечения в этот каталог. Вот пример сценария завершения bash для Rsync:

# bash completion for rsynchave 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, который наиболее точно соответствует вашей программе. Одним из простейших примеров является rrdtool файл.

Если все, что вам нужно, - это простое автоматическое завершение на основе слов (так что никакого завершения подкоманды или чего-то еще), то complete команда имеет -W вариант, который просто делает правильные вещи.

Например, у меня есть следующие строки в моем .bashrc для автозаполнения программы, вызываемой юпитер:

# gleaned from `jupyter --help`_jupyter_options='console qtconsole notebook' # shortened for this answercomplete -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 necessaryif [[ -n "$ZSH_VERSION" ]]; then    autoload bashcompinit    bashcompinitfi

Просто добавляю это сюда на случай, если это кому-нибудь поможет.

Помимо примеров, окончательным источником / ссылкой для получения дополнительной информации по этой теме является само руководство по bash (т.е. Введите man bash в терминале)

Поиск по заголовкам "Завершение" и "Программируемое завершение". (в текущей версии документации bash они отображаются в строках 2219 и 2332 соответственно), а также соответствующие встроенные ключевые слова bash, на которые ссылаются в этих разделах (например, compgen (строка 2627), complete (строка 2637) и т.д.)

при использовании скрипта в консоли

объясните “сценарий bash”, вы имеете в виду при редактировании сценария? что ты хочешь с этим делать?

Что касается места, куда поместить ваши дополнения, см. этот вопрос, а также комментарии к принятому ответу там.