Wie erstelle ich ein Skript mit Auto-Vervollständigung?

95

Wenn ich Programm wie svn benutze und Gnome Terminal eintippe:

svn upd

und drücken Sie Tab es ist automatisch vervollkommnet zu:

svn update

Ist es möglich, etwas in meinem benutzerdefinierten Bash-Skript zu tun?

    
UAdapter 17.10.2011, 17:12
quelle

5 Antworten

33

Sie können die Programmable Completion verwenden. Schauen Sie sich für einige Beispiele /etc/bash_completion und /etc/bash_completion.d/* an.

    
Florian Diesch 17.10.2011, 17:54
quelle
159

Ich bin sechs Monate zu spät, aber ich war auf der Suche nach dem gleichen und fand das:

Sie müssen eine neue Datei erstellen:

/etc/bash_completion.d/foo

Fügen Sie für eine statische Autovervollständigung ( --help / --verbose zum Beispiel) Folgendes hinzu:

_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 ist ein Array, das alle einzelnen Wörter in der aktuellen Befehlszeile enthält.
  • COMP_CWORD ist ein Index des Wortes, das die aktuelle Cursorposition enthält.
  • COMPREPLY ist eine Arrayvariable, aus der Bash die möglichen Vervollständigungen liest.

Und der Befehl compgen gibt das Array von Elementen aus --help , --verbose und --version zurück, die mit dem aktuellen Wort "${cur}" übereinstimmen:

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

Quelle: Pfandrecht

    
Louis Soulez 13.09.2013 17:41
quelle
33

Alle Bash-Vervollständigungen werden in /etc/bash_completion.d/ gespeichert. Wenn Sie also Software mit bash_completion erstellen, wäre es sinnvoll, wenn die deb / make-Installation eine Datei mit dem Namen der Software in diesem Verzeichnis ablegt. Hier ist ein Beispiel für ein Bash-Vervollständigungsscript für 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

Es würde sich wahrscheinlich lohnen, eine der bash-Vervollständigungsdateien dort zu überprüfen, die am ehesten zu Ihrem Programm passen. Eines der einfachsten Beispiele ist die Datei rrdtool .

    
Marco Ceppi 13.01.2012 18:28
quelle
28

Hier ist ein komplettes Tutorial.

Lassen Sie uns ein Beispiel für ein Skript namens admin.sh geben, zu dem Sie eine automatische Vervollständigung wünschen.

#!/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

Bitte beachten Sie die Auswahlliste. Wenn Sie ein Skript mit dieser Option aufrufen, werden alle möglichen Optionen für dieses Skript ausgegeben.

Und hier haben Sie das Autocomplete-Skript:

_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

Beachten Sie, dass das letzte zu vervollständigende Argument der Name des Skripts ist, dem Sie die automatische Vervollständigung hinzufügen möchten. Alles, was Sie tun müssen, ist, Ihr Autocomplete-Skript zu bashrc als

hinzuzufügen
source /path/to/your/autocomplete.sh

oder kopieren Sie es nach     /etc/bash.completion.d

    
kokosing 14.06.2014 12:33
quelle
7

Wenn Sie nur eine einfache wortbasierte automatische Vervollständigung wünschen (also keine Unterbefehlsvervollständigung oder irgendetwas), hat der complete -Befehl eine -W -Option, die genau das Richtige tut.

Zum Beispiel habe ich die folgenden Zeilen in meinem .bashrc , um ein Programm namens jupyter automatisch zu vervollständigen:

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

Jetzt jupyter <TAB> <TAB> autocompletes für mich.

Die Dokumente auf gnu.org sind hilfreich.

Es scheint sich darauf zu verlassen, dass die IFS Variable richtig gesetzt ist, aber das hat für mich keine Probleme verursacht.

Verwenden Sie die Option -o :

, um die Dateinamenergänzung und die Standard-BASH-Vervollständigung hinzuzufügen
complete -W "${_jupyter_options}" -o bashdefault -o default 'jupyter'

Um dies in zsh zu verwenden, fügen Sie den folgenden Code hinzu, bevor Sie den Befehl complete in Ihrem ~/.zshrc ausführen:

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

Tags und Links