it-swarm.com.de

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

Wenn ich ein Programm wie svn verwende und Gnome Terminal eintippe:

svn upd

und schlagen Tab Es wird automatisch vervollständigt zu:

svn update

Kann ich so etwas in meinem benutzerdefinierten Bash-Skript tun?

118
UAdapter

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

42
Florian Diesch

Ich bin ein halbes Jahr zu spät, habe aber dasselbe gesucht und folgendes herausgefunden:

Sie müssen eine neue Datei erstellen:

/etc/bash_completion.d/foo

Fügen Sie für eine statische Autovervollständigung (--help/--verbose) 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 Array-Variable, 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 dem aktuellen Wort "${cur}" entsprechen:

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

Quelle: http://www.debian-administration.org/articles/316

203
Louis Soulez

Alle Bash-Vervollständigungen werden in /etc/bash_completion.d/ gespeichert. Wenn Sie also Software mit bash_completion erstellen, lohnt es sich, die Datei deb/make install mit dem Namen der Software in diesem Verzeichnis abzulegen. Hier ist ein Beispiel für ein Bash-Abschlussskript 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
    [email protected](config|password-file|include-from|exclude-from))
        _filedir
        return 0
        ;;
    [email protected](T|-temp-dir|-compare-dest))
        _filedir -d
        return 0
        ;;
    [email protected](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]}" == [email protected](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-Abschlussdateien zu lesen, die Ihrem Programm am ehesten entspricht. Eines der einfachsten Beispiele ist die Datei rrdtool.

34
Marco Ceppi

Hier ist ein komplettes Tutorial.

Nehmen wir ein Beispiel für ein Skript mit dem Namen admin.sh, an dem die automatische Vervollständigung ausgeführt werden soll.

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

Optionsauswahlliste beachten. Wenn Sie das Skript mit dieser Option aufrufen, werden alle möglichen Optionen für dieses Skript ausgedruckt.

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, zu dem Sie die automatische Vervollständigung hinzufügen möchten. Alles was Sie tun müssen, ist Ihr Autocomplete-Skript zu bashrc as hinzuzufügen

source /path/to/your/autocomplete.sh

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

33
kokosing

Wenn Sie nur eine einfache, auf Word basierende automatische Vervollständigung wünschen (also keine Vervollständigung von Unterbefehlen oder ähnliches), verfügt der Befehl complete über die Option -W, 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 wird jupyter <TAB> <TAB> für mich automatisch vervollständigt.

Die docs bei gnu.org sind hilfreich.

Es scheint, dass die Variable IFS korrekt eingestellt ist, aber das hat für mich keine Probleme verursacht.

Verwenden Sie die Option -o, um die Dateinamenvervollständigung 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
10
Ben