Comment créer un script avec auto-complete?

95

Lorsque j'utilise un programme tel que svn et que je tape dans Gnome Terminal:

svn upd

et appuyez sur Tab il est automatiquement terminé à:

svn update

Est-il possible de faire quelque chose comme ça dans mon script bash personnalisé?

    
posée UAdapter 17.10.2011 - 17:12
la source

5 réponses

33

Vous pouvez utiliser le achèvement programmable . Regardez /etc/bash_completion et /etc/bash_completion.d/* pour quelques exemples.

    
réponse donnée Florian Diesch 17.10.2011 - 17:54
la source
159

J'ai six mois de retard mais je cherchais la même chose et j'ai trouvé ceci:

Vous devrez créer un nouveau fichier:

/etc/bash_completion.d/foo

Pour une saisie automatique statique ( --help / --verbose par exemple), ajoutez ceci:

_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 est un tableau contenant tous les mots individuels de la ligne de commande en cours.
  • COMP_CWORD est un index du mot contenant la position actuelle du curseur.
  • COMPREPLY est une variable de tableau à partir de laquelle Bash lit les complétions possibles.

Et la commande compgen renvoie le tableau des éléments --help , --verbose et --version correspondant au mot actuel "${cur}" :

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

Source: lien

    
réponse donnée Louis Soulez 13.09.2013 - 17:41
la source
33

Toutes les complétions de bash sont stockées dans /etc/bash_completion.d/ . Donc, si vous construisez un logiciel avec bash_completion, il serait intéressant que deb / make installe un fichier contenant le nom du logiciel dans ce répertoire. Voici un exemple de script d’achèvement de bash pour 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

Il serait probablement intéressant d’examiner l’un des fichiers d’achèvement de bash qui correspond le mieux à votre programme. L'un des exemples les plus simples est le fichier rrdtool .

    
réponse donnée Marco Ceppi 13.01.2012 - 18:28
la source
28

Voici un tutoriel complet.

Avons un exemple de script appelé admin.sh auquel vous souhaitez que le remplissage automatique fonctionne.

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

Notez la liste des options. L'appel du script avec cette option imprimera toutes les options possibles pour ce script.

Et voici le script de saisie semi-automatique:

_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

Notez que le dernier argument à compléter est le nom du script auquel vous souhaitez ajouter la saisie semi-automatique. Tout ce que vous avez à faire est d'ajouter votre script de saisie semi-automatique à bashrc en tant que

source /path/to/your/autocomplete.sh

ou le copier dans     /etc/bash.completion.d

    
réponse donnée kokosing 14.06.2014 - 12:33
la source
7

Si tout ce que vous voulez, c'est une auto-complétion simple basée sur des mots (donc aucune complétion de sous-commande ou autre), la commande complete a une option -W qui fait juste la bonne chose.

Par exemple, j'ai les lignes suivantes dans mon .bashrc pour compléter automatiquement un programme appelé jupyter :

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

Maintenant, jupyter <TAB> <TAB> autocompletes pour moi.

Les documents sur gnu.org sont utiles.

Il semble que la variable IFS soit définie correctement, mais cela n’a causé aucun problème pour moi.

Pour ajouter la fin du nom de fichier et l’achèvement de BASH par défaut, utilisez l’option -o :

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

Pour utiliser ceci dans zsh, ajoutez le code suivant avant d’exécuter la commande complete dans votre ~/.zshrc :

# make zsh emulate bash if necessary
if [[ -n "$ZSH_VERSION" ]]; then
    autoload bashcompinit
    bashcompinit
fi
    
réponse donnée Ben 28.11.2016 - 01:04
la source

Lire d'autres questions sur les étiquettes