Aggiungere il completamento automatico (Tab) ai tuoi script Bash e zsh

Perché aggiungere il completamento automatico
Il completamento tramite Tab è una funzionalità semplice ma potente: riduce gli errori di digitazione, accelera il lavoro, e aiuta a scoprire sottocomandi e opzioni disponibili senza leggere la documentazione. Molti utenti si aspettano che i comandi forniscano completamento; non averlo è una piccola frizione che può abbassare l’adozione del tuo strumento.
Definizione rapida: Il completamento automatico è il meccanismo che suggerisce o completa parole nel terminale mentre digiti, basandosi sul contesto (comando, percorso file, opzioni, ecc.).
Come funziona il completamento nel terminale
I shell come zsh e Bash gestiscono il completamento in modi diversi, ma concettualmente ci sono tre tipi principali:
- Comandi: completamento del nome del comando cercando nelle directory indicate da PATH.
- Percorsi/file: completamento di nomi di file e directory.
- Argomenti e sottocomandi: completamento contestuale di opzioni, sotto-strumenti o valori possibili dopo il nome del comando.
Il completamento contestuale (argomenti) è spesso la parte più utile per script personalizzati: permette di suggerire sottocomandi, file speciali o valori validi per un’opzione.
Un esempio pratico: il comando todos
Useremo un semplice script fittizio chiamato todos che gestisce una lista di attività. L’esempio è minimale e focalizzato solo sul completamento dei sottocomandi.
#!/usr/bin/env zsh
FILE="$HOME/.local/state/todos/data"
if [ "$#" -eq "1" ] && [ "$1" = "edit" ] ; then
"${EDITOR:-vi}" "$FILE"
elif [ "$#" -eq "1" ] && [ "$1" = "help" ] ; then
echo "Usage: $(basename $0) [ edit | help ]"
else
<"$FILE" grep -v ^~
fi
Comandi disponibili dopo l’installazione di questo script in PATH e con permessi eseguibili:
- todos — mostra il contenuto del file dati, ignorando righe che iniziano con ~
- todos help — mostra l’uso
- todos edit — apre il file dei todo nell’editor
Questo è tutto ciò che ci serve per dimostrare il completamento degli argomenti.
Completamento personalizzato in zsh
La versione più semplice per zsh sfrutta il modulo compinit e la funzione compadd. Copia e incolla questo frammento nella tua ~/.zshrc o in un file sotto una directory elencata in fpath (nome del file che inizia con underscore):
_complete_todos() {
compadd help edit
}
autoload -Uz compinit
compinit
compdef _complete_todos todos
Spiegazione rapida:
- _complete_todos è il gestore di completamento: chiama compadd con la lista delle possibili opzioni.
- compinit attiva il sistema di completamento di zsh.
- compdef collega la funzione _complete_todos al comando todos.
Importante: puoi mettere lo stesso codice in un file separato e caricarlo dalla tua ~/.zshrc con un semplice source.
Differenze e peculiarità di Bash
Bash funziona in modo più esplicito: il gestore deve popolare la variabile array COMPREPLY. Bash non applica automaticamente filtri di prefisso, quindi il tuo gestore dovrebbe tenere conto del testo parziale già digitato.
Esempio naïf in Bash:
_complete_todos_bash() {
COMPREPLY=(help edit)
}
complete -F _complete_todos_bash todos
Questo funziona, ma non filtra per il prefisso digitato:
$ todos he
help edit
Per produrre suggerimenti contestuali usa le variabili che Bash mette a disposizione:
- COMP_WORDS: array con ogni parola della riga di comando.
- COMP_CWORD: indice corrente nella riga di comando (la parola su cui si sta completando).
Il comando compgen semplifica la generazione di completamenti basati su una lista statica. Esempio:
$ compgen -W "one two three" o
one
$ compgen -W "one two three" t
two
three
Un gestore completo minimale che filtra per prefisso:
_complete_todos_bash() {
COMPREPLY=( $( compgen -W "edit help" -- "${COMP_WORDS[$COMP_CWORD]}" ) )
}
complete -F _complete_todos_bash todos
Script portabile che funziona in zsh e Bash
Per rendere il completamento riutilizzabile su più sistemi, conviene scrivere un singolo file che rilevi la shell in esecuzione e registri il gestore appropriato.
SUBCOMMANDS=(help edit halt)
_complete_todos_zsh() {
compadd $SUBCOMMANDS
}
_complete_todos_bash() {
COMPREPLY=( $( compgen -W "${SUBCOMMANDS[*]}" -- "${COMP_WORDS[$COMP_CWORD]}" ) )
}
if [ -n "${ZSH_VERSION:-}" ]; then
autoload -Uz compinit
compinit
compdef _complete_todos_zsh todos
elif [ -n "${BASH_VERSION:-}" ]; then
complete -F _complete_todos_bash todos
fi
Nota: ZSH_VERSION e BASH_VERSION esistono solo nella shell che invoca il completamento; è la shell dell’utente (dove si preme Tab) che conta, non la shell in cui è stato eseguito lo script originale.
Consigli pratici per script reali
- Mantieni una lista centrale di suggerimenti (es. SUBCOMMANDS) e sfruttala in entrambi i gestori.
- Per sottocomandi dinamici, genera la lista al volo (es. leggendo un file, interrogando l’applicazione o chiamando il comando con –list).
- Considera l’uso di standard come l’opzione –generate-completion (molti progetti usano questa convenzione) per lasciare che il programma fornisca i suggerimenti più aggiornati.
- Evita operazioni lente nel gestore: il completamento è interattivo e deve rispondere rapidamente.
Importante: esegui sempre il completamento in modo idempotente e senza effetti collaterali (non modificare file o stato dell’ambiente).
Quando il completamento fallisce o è poco utile
- Script che fanno operazioni lente o bloccanti (network, I/O pesante) se vengono chiamati dal gestore di completamento. Evita di eseguire comandi costosi durante la generazione delle liste.
- Input che dipende da stato remoto non immediatamente disponibile. In questi casi fornisci una cache o un’opzione esplicita per rigenerare l’elenco.
- Ambiente in cui l’utente non ha caricato il file di completamento (non è stato fatto source o non è stato installato globalmente).
- Bash senza il corretto uso di COMP_WORDS/COMP_CWORD: suggerimenti che non rispettano il prefisso.
Contromisure:
- Fornisci un fallback statico.
- Introduci un timeout o una cache per le operazioni remote.
- Documenta come installare il completamento.
Approcci alternativi e integrazioni
- Usare framework di completamento avanzati: per zsh esistono plugin e helper che semplificano la scrittura di completamenti complessi.
- Delegare al programma: molti progetti espongono un sottocomando per il completamento (es. myprog –completion zsh) in modo che lo script di completamento invochi il programma per ottenere suggerimenti aggiornati.
- Strumenti esterni come argcomplete (per Python) che si integrano con Bash e offrono mappature automatiche delle opzioni.
Quando usare quale approccio:
- Script piccoli e personali: gestore statico in ~/.bashrc o ~/.zshrc.
- Progetti condivisi: un file di completamento installabile (es. /etc/bash_completion.d/) o una funzione che chiede al programma i suggerimenti.
Mini-metodologia per progettare un completamento
- Identifica i contesti da completare: sottocomandi, opzioni, file, valori predefiniti.
- Definisci la sorgente dei suggerimenti: lista statica, output di un comando, file di configurazione.
- Implementa gestori separati per zsh e Bash, riutilizzando la stessa sorgente.
- Misura i tempi di risposta e aggiungi caching se necessario.
- Scrivi test di accettazione per i casi principali.
- Documenta l’installazione e fornisci una procedura per aggiornamenti.
Checklist per ruolo
Sviluppatore:
- Avere una lista centrale di sottocomandi e opzioni.
- Garantire che il gestore non modifichi lo stato.
- Offrire un modo per rigenerare la lista di suggerimenti.
Operazioni / Packager:
- Installare il file di completamento in /etc/bash_completion.d/ o in una directory compatibile per zsh.
- Aggiornare la documentazione di installazione.
Utente finale:
- Eseguire source /path/to/completion.sh oppure riavviare la shell dopo l’installazione.
- Verificare con il comando compgen (Bash) o compadd (zsh) per debug.
Test di accettazione e casi di prova
Casi minimi che dovresti coprire:
- Completamento di tutti i sottocomandi dopo “todos
”. - Completamento parziale: “todos he
” deve suggerire solo “help”. - Completamento in presenza di altri argomenti: “todos edit –
” non deve accidentalmente suggerire sottocomandi al posto di opzioni. - Prestazioni: generazione dei suggerimenti in meno di 200 ms per user experience fluida (criterio qualitativo se non misurabile automaticamente).
Esempio di comando di test rapido per Bash:
# Fornisce l'ultima parola su cui il completamento si applica
echo "COMP_WORDS: ${COMP_WORDS[*]}"
echo "COMP_CWORD: ${COMP_CWORD}"
Snippets e cheat sheet
- Registrare completamento in zsh: compdef _function comando
- Registrare completamento in Bash: complete -F _function comando
- Generare completamenti filtrati in Bash: compgen -W “list” – “${COMP_WORDS[$COMP_CWORD]}”
- Aggiungere compadd in zsh: compadd item1 item2
Esempio avanzato: completamento dinamico basato su file di configurazione
Questo approccio legge una lista di elementi da un file JSON o da una directory e li serve come suggerimenti senza lanciare comandi pesanti.
Mental model: pensa al completamento come a un query a bassa latenza che legge una sorgente locale già disponibile (file o cache). Se devi fare chiamate di rete, ragiona su un livello di caching o su un processo asincrono che aggiorna una cache locale.
Compatibilità e migrazione
- Per Bash, assicurati che la distribuzione includa il pacchetto bash-completion o che sia configurata manualmente.
- Per zsh, verifica che compinit sia presente e che fpath contenga la directory dove metti il file _nome.
- Se distribuisci il completamento in un pacchetto, aggiungi gli script nei percorsi standard (/usr/share/zsh/site-functions o /etc/bash_completion.d/). Documenta la versione minima di shell supportata.
Sicurezza e privacy
- Non esporre dati sensibili nei suggerimenti (es. token, password, percorsi con dati privati).
- Evita di eseguire comandi che potrebbero ritornare informazioni sensibili o modificare lo stato.
- Quando il completamento legge file utente, assicurati che i permessi siano appropriati e documenta cosa viene letto.
Distribuzione e procedura di rollout
Sempilla SOP per rilasciare il completamento ai tuoi utenti:
- Preparare il file completion.sh o _todos (per zsh) con i gestori.
- Inserire il file nel pacchetto del progetto sotto /share/completions/.
- Aggiornare lo script di installazione per copiare i file in /etc/bash_completion.d/ e /usr/share/zsh/site-functions/.
- Aggiornare la documentazione di installazione con i comandi per forzare il reload (source ~/.bashrc o exec zsh).
- Comunicare agli utenti la nuova funzionalità e come disabilitarla se necessario.
Edge case e quando preferire l’output statico
- Utenti con shell minime o container molto ridotti dove non è presente bash-completion o compinit: preferisci un file di completamento statico facilmente installabile a mano.
- Script che cambiano spesso l’elenco dei sottocomandi: considera la generazione automatica di file di completamento durante la fase di build/release.
Glossario rapido
- compadd: funzione di zsh che aggiunge suggerimenti al sistema di completamento.
- compgen: comando di utilità di Bash per generare completamenti da una lista.
- COMPREPLY: array di Bash che il gestore deve popolare con i suggerimenti.
- compinit: modulo di zsh che abilita il sistema di completamento.
Riepilogo
- Il completamento con Tab migliora l’usabilità dei tuoi script e può essere implementato in poche righe per zsh e Bash.
- zsh fornisce astrazioni più semplici (compadd, compinit), Bash richiede una gestione esplicita tramite COMPREPLY e compgen.
- Per progetti condivisi crea un file di completamento portabile e documenta l’installazione.
- Evita operazioni lente e non esporre dati sensibili durante la generazione dei suggerimenti.
Importante: prova sempre il completamento nelle shell e negli ambienti target e includi test e istruzioni per l’installazione.
Breve checklist finale:
- Funzionalità base implementata per zsh e Bash
- Documentazione di installazione aggiornata
- Test di accettazione automatizzati o manuali completati
- Verificato che non vengono esposti dati sensibili
Grazie per aver letto: ora prova a creare un file completion.sh basato sull’esempio e adattalo al tuo strumento.
Materiali simili

Creare Video Overview con NotebookLM

Bloccare le app Android in background e risparmiare batteria
Ridimensionare array RAID degradato su Linux

Tracciare e difendersi dai numeri falsi

Completamento Tab per script Bash e zsh
