Jak vytvořit skript s automatickým dokončováním?

98

Když používám program jakosvn a píšu v terminálu Gnome:

svn upd

a stisknutím Tab se automaticky dokončí:

svn update

Je možné něco takového udělat v mém vlastním bash skriptu?

    
dané UAdapter 17.10.2011 17:12

5 odpovědí

35

Můžete použít Programovatelné dokončení . Podívejte se na/etc/bash_completion a/etc/bash_completion.d/* pro některé příklady.

    
odpověděl Florian Diesch 17.10.2011 17:54
163

Jsem o šest měsíců pozdě, ale hledal jsem totéž a našel jsem to:

Budete muset vytvořit nový soubor:

/etc/bash_completion.d/foo

Pro statické automatické doplnění (například--help /--verbose) přidejte toto:

_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 je pole obsahující všechny jednotlivé slova v aktuálním příkazovém řádku.
  • COMP_CWORD je index slova obsahující aktuální pozici kurzoru.
  • COMPREPLY je proměnná pole, ze které Bash přečte možné dokončení.

A příkazcompgen vrací pole elementů z--help,--verbose a--version odpovídající aktuálnímu slovu"${cur}":

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

Zdroj: Odkaz

    
odpověděl Louis Soulez 13.09.2013 17:41
33

Všechna dokončení bash jsou uložena v/etc/bash_completion.d/. Takže pokud budujete software s bash_completion, bylo by vhodné, abyste deb / make install spustili soubor se jménem softwaru v tomto adresáři. Zde je příklad skriptu dokončení bash pro Rsync:

# 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

Bude pravděpodobně užitečné přezkoumat jeden z souborů dokončení bash, které nejvíce odpovídají vašemu programu. Jedním z nejjednodušších příkladů je souborrrdtool.

    
odpověděl Marco Ceppi 13.01.2012 18:28
29

Zde je kompletní návod.

Umožňuje příklad skriptu nazvaného admin.sh, do kterého byste chtěli mít automatickou práci.

#!/bin/bash

while [ $# -gt 0 ]; do
  arg=
  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

Seznam možností výběru poznámky. Volání skriptu s touto volbou vytiskne všechny možné možnosti tohoto skriptu.

A zde máte skript automatického dokončování:

_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

Všimněte si, že poslední argument, který chcete dokončit, je název skriptu, do kterého chcete přidat automatické dokončování. Jediné, co musíte udělat, je přidat skript automatického dokončování do souboru bashrc jako

source /path/to/your/autocomplete.sh

nebo jej zkopírujte     /etc/bash.completion.d

    
odpověděl kokosing 14.06.2014 12:33
8

Pokud vše, co chcete, je jednoduché na základě automatického dokončování slov (tak žádné dokončení dílčího příkazu nebo cokoli jiného), příkazcomplete má volbu-W, která právě dělá správnou věc.

Například mám v mém.bashrc následující řádky k automatickému dokončení programu s názvem jupyter :

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

Nyníjupyter <TAB> <TAB> autocompletes pro mě.

dokumenty na gnu.org jsou užitečné.

Zdá se, že se spoléhá na správnou proměnnouIFS, která však pro mě nezpůsobila žádné problémy.

Chcete-li přidat doplnění názvu souboru a výchozí dokončení BASH, použijte volbu-o:

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

Chcete-li tuto funkci použít v zsh, přidejte následující kód před spuštěním příkazucomplete ve složce~/.zshrc:

# make zsh emulate bash if necessary
if [[ -n "$ZSH_VERSION" ]]; then
    autoload bashcompinit
    bashcompinit
fi
    
odpověděl Ben 28.11.2016 01:04