Quand j'utilise un programme comme svn
et que je tape dans Gnome Terminal:
svn upd
et frapper Tab c'est auto-complété à:
svn update
Est-il possible de faire quelque chose comme ça dans mon script bash personnalisé?
Vous pouvez utiliser le Fin programmable . Regardez /etc/bash_completion
et /etc/bash_completion.d/*
pour quelques exemples.
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 complétion 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 de la ligne de commande actuelle.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 de --help
, --verbose
et --version
correspondant au mot Word "${cur}"
actuel:
compgen -W "--help --verbose --version" -- "<userinput>"
Toutes les finitions de bash sont stockées dans /etc/bash_completion.d/
. Donc, si vous construisez un logiciel avec bash_completion, il serait intéressant de demander à deb/make install de déposer un fichier avec 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
--@(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
Il serait probablement intéressant d’examiner l’un des fichiers de fin d’essais correspondant à votre programme. L'un des exemples les plus simples est le fichier rrdtool
.
Voici un tutoriel complet.
Donnons un exemple de script appelé admin.sh auquel vous souhaiteriez que la saisie semi-automatique fonctionne.
#!/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
Notez la liste des options. Appeler un script avec cette option affichera toutes les options possibles pour ce script.
Et ici vous avez le script autocomplete:
_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 complétion automatique. Tout ce que vous avez à faire est d’ajouter votre script autocomplete à bashrc as
source /path/to/your/autocomplete.sh
ou le copier dans /etc/bash.completion.d
Si tout ce que vous voulez, c'est une simple complétion automatique basée sur Word (donc aucune complétion de sous-commande ou quoi que ce soit), la commande complete
a une option -W
qui fait juste ce qu'il faut.
Par exemple, mon .bashrc
contient les lignes suivantes 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'
jupyter <TAB> <TAB>
s'auto-complète maintenant.
Les docs à gnu.org sont utiles.
Il semble que la variable IFS
soit correctement définie, mais cela ne m'a posé aucun problème.
Pour ajouter l'achèvement 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 cela 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