Problemi in questa pagina? Segnalali in questa discussione
Introduzione
Prima di vedere nel dettaglio gli strumenti che le varie shell disponibili su Ubuntu forniscono per fare il parsing della riga di comando, è utile fare una breve introduzione per capire alcuni concetti fondamentali.
Facendo riferimento al comando tar, un modo generico per lanciare questo comando nel terminale è dato da:
tar -cv -f mioArchivio.tar directoryDaArchiviare
Il comando è composto da una serie di stringhe dette argomenti. Il primo argomento è il nome stesso del comando, mentre i successivi sono indicati con il nome di parametri posizionali.
Questi ultimi possono essere suddivisi in alcune categorie logiche:
una opzione è un argomento, generalmente incluso nella documentazione del comando, la cui presenza modifica il comportamento del comando stesso.
Una opzione può esistere nella versione corta, che consiste in un trattino seguito da una singola lettera (ad esempio, '-f' nel comando precedente), o nella versione lunga. Di quest'ultima, si hanno due formati: nello stile GNU si ha un doppio trattino seguito da una serie di due o più lettere (ad esempio '--help'); lo stile XF86 ha un singolo trattino come prefisso (ad esempio '-verbose').
Più opzioni corte possono essere raggruppate in un singolo argomento (ad esempio, '-cv' nel comando precedente).un parametro è un argomento che può fornire informazioni aggiuntive al comando o a un'opzione a cui si riferisce. Nel comando precedente, 'mioArchivio.tar' è un parametro dell'opzione '-f', mentre 'directoryDaArchiviare' è un parametro per il comando 'tar'. Qualora si volesse aggiungere al comando un parametro che ha l'aspetto di una opzione, ma non la sua funzione, è possibile separarlo dal resto del comando scrivendolo dopo un doppio trattino '--'
Fatta questa premessa, è utile notare che il comando precedente è equivalente al comando:
tar -vcf mioArchivio.tar directoryDaArchiviare
In questo comando, tutte le opzioni corte sono state riunite e ne è stato cambiato l'ordine. Analogamente, l'ordine con cui vengono scritte le opzioni lunghe, insieme ai loro eventuali parametri, non ne altera il significato.
Il parsing della riga di comando è quindi la procedura con cui un comando, o uno script, interpretano le istruzioni fornite dall'utente tramite una opportuna combinazione di opzioni e parametri. Nel caso di uno script, per poter effettuare facilmente questo parsing, si possono usare due strumenti molto versatili: getopt e getopts (fare attenzione alla 's' finale nel secondo comando).
getopt
Il comando getopt analizza una stringa di parametri e ne restituisce una versione canonica, che potrà poi essere analizzata più facilmente.
Pro
Contro
Il comando getopt descritto in questa guida non è un built-in della shell, ma è attualmente incluso nel pacchetto utils-linux e precedentemente nella glibc (cioè, la GNU lib c).
getopt --Test
Funzionamento
Il comando getopt può essere chiamato con tre diverse sintassi. La più semplice è:
getopt optstring parameters
optsting è una stringa che informa il comando relativamente alle opzioni nel formato corto che possono essere trovate durante il parsing. Questa stringa deve essere racchiusa tra doppi apici, inoltre: se il carattere che indica l'opzione è seguito dai due punti, l'opzione accetta un parametro obbligatorio; se è seguito da una coppia di doppi punti, accetta un parametro opzionale. parameters indica invece a getopt la stringa degli argomenti su cui operare. Generalmente si indica come parameters la string dei parametri posizionali passati allo script, cioè "$@"; se si vuole passare una stringa alternativa, questa non va racchiusa tra apici, né singoli né doppi.
Le altre due sintassi hanno rispettivamente la forma
getopt [options] [--] optstring parameters
e
getopt [options] -o|--options optstring [options] [--] parameters
in cui optstring e parameters sono gli stessi visti nella prima sintassi, mentre le parti racchiuse tra le parentesi quadre sono opzionali e la barra verticale indica che l'opzione alla sua sinistra e quella alla sua destra sono equivalenti.
La stringa options, che nella seconda sintassi può essere presente senza ripetizioni in due punti, contiene una serie di opzioni e rispettivi parametri che modificano il funzionamento del comando. Tra queste, le più importanti sono:
-l|--longoptions longopts
permette di indicare al comando che durante il parsing potrà incontrare opzioni lunghe, che, analogamente alle opzioni corte, vengono specificate nella stringa longopts. Questa stringa va racchiusa tra doppi apici e le opzioni al suo interno vanno separate con una virgola. Inoltre, se la stringa che indica l'opzione lunga è seguita dai due punti, questa accetta un parametro obbligatorio; se è seguita da una coppia di doppi punti, accetta un parametro facoltativo.
-a|--alternative
abilita la stile XF86 per le opzioni lunghe.
-q|--quiet
disabilita l'output degli errori da parte di getopt.
-Q|--quiet-output
indica a getopt di non produrre il suo output, ma gli errori incontrati nel parsing vengono ancora riportati.
Esempi d'uso
I seguenti esempi d'uso mostrano come chiamare getopt facendo riferimento, rispettivamente, alle tre sintassi viste:
getopt "hf:d::" $@
Con questa chiamata, getopt potrà accettare l'opzione 'h' senza parametro, l'opzione 'v' con un parametro obbligatorio e l'opzione 't' con un parametro facoltativo.
getopt -l "help,file:,dir::,verbose" -- "hf:d::" "$@"
Qui getopt accetta anche le opzioni nella versione lunga '--file', con un parametro obbligatorio, e '--dir' con un parametro facoltativo.
getopt
Considerazioni sugli esempi d'uso
getopts
Pro
A differenza di getopt, il comando getopts è un built-in della shell. Questo comporta che:
è definito nello standard POSIX non c'è quindi bisogno di fare attenzione alle sue diverse implementazioni, come avviene per getopt;
- non ha bisogno di programmi esterni per accedere ai parametri posizionali;
- può avere accesso diretto alle variabili della shell, che può usare per fare il parsing.
Contro
Il comando getops è in grado di fare il parsing solo delle opzioni corte. Se lo script prevede l'uso di opzioni lunghe, sia nello stile GNU sia nello stile XF86, getopts non è la scelta opportuna.
Funzionamento
La sintassi del comando è:
getopts optstring varname [args]
in cui
Parametro |
Descrizione |
optstring |
È una stringa che istruisce il comando getopts relativamente a quali opzioni aspettarsi e quando siano previsti i relativi parametri. |
varname |
È una stringa che rappresenta il nome della variabile della shell in cui il comando getopts inserisce il valore delle opzioni lette. |
args |
È una stringa opzionale. Di default getopts fa il parsing dei parametri posizionali, cioè della stringa $@; se è presente una stringa args, farà il parsing dei parametri contenuti in quest'ultima. |
Come visto nella tabella, il comando getopts viene istruito sulle opzioni e gli eventuali parametri che si può aspettare tramite optstring. La sintassi di questa stringa è molto semplice.
- Ogni opzione che si vuole aggiungere, viene indicata con la relativa lettera. Per le opzioni non sono consentiti i caratteri ':' e '?'.
Se l'opzione prevede un parametro ad essa associato, il carattere associato all'opzione in optstring va fatto seguire dal carattere ':'. Quindi, se si vuole aggiungere l'opzione 'f' e a questa si vuole associare un parametro, nella stringa optstring si aggiungerà la sequenza 'f:'
Il comando getopts può essere impostato nella modalità silenziosa, aggiungendo il carattere ':' come suffisso di optstring. Se questo carattere è assente, getopts è in modalità verbosa. La differenza consiste nel fatto che nel secondo caso produrrà dei messaggi qualora rilevasse degli errori durante il parsing. Generalmente, si opta per la modalità silenziosa e la gestione autonoma dei messaggi d'errore. Inoltre, tramite la variabile OPTERR (vedi sotto) si può comunque silenziare la stampa dei messaggi di errore nella modalità verbosa.
Se, ad esempio, volessimo che getopts si aspetti di incontrare nel parsing le opzione 'v' ed 'h' senza parametri associati e l'opzione 'f' con un parametro associato, optstring sarebbe uguale a "vhf:" per la modalità verbosa e uguale a ":vhf:" per quella silenziosa.
Per il suo funzionamento, getopts usa le seguenti variabili
Variabile |
Descrizione |
OPTIND |
È una variabile della shell, che contiene l'indice del parametro posizionale del prossimo argomento da processare. Viene modificata da getopts, che la usa per tenere traccia del proprio stato. Torna utile anche per poter fare uno shift dei parametri posizionali, dopo averli analizzati con getopts. |
OPTARG |
Viene impostata al valore dell'argomento relativo a ogni parametro trovato da getopts. Se l'opzione passata è sconosciuta, viene impostato al valore dell'opzione. |
OPTERR |
È una variabile di bash che può assumere il valore 1 o 0, a seconda che si desideri o meno che la shell mostri il messaggio d'errore generato automaticamente da getopts. Di default è impostata ad 1 e ha senso modificarla solo nella modalità verbosa. Non è supportata in shell quali ksh93, mksh, zsh, or dash. |
La gestione del parametro varname e della variabile OPTARG cambia a seconda della modalità in cui si usa getopts ed è riassunta nella seguente tabella.
Modalità verbosa |
||
opzione |
varname è posto uguale al carattere '?' |
|
parametro obbligatorio |
varname è posto uguale al carattere '?' |
Modalità silenziosa |
||
opzione |
varname è posto uguale al carattere '?' |
|
parametro obbligatorio |
varname è posto uguale al carattere ':' |
Esempi d'uso
Il comando viene usato all'interno di un ciclo while. Ad ogni iterazione del ciclo, legge un'opzione, e l'eventuale parametro associato, dalla stringa dei parametri posizionali forniti allo script (o da args, se fornita); se tutto è corretto, aggiorna le sue variabili interne, secondo quanto visto al punto precedente, e fornisce questi dati all'utente per la loro analisi, generalmente all'interno di un costrutto case. Il comando restituisce un exit status 1 quando non ci sono più parametri da leggere, facendo terminare il ciclo. Inoltre, il comando interrompe il parsing se incontra la sequenza di caratteri '--'.
Modalità verbosa
#!/usr/bin/env bash while getopts "vg:uf:" option; do case $option in v ) echo "Passata l'opzione: -$option" echo "Non ha un parametro associato, quindi OPTARG=$OPTARG" echo "Il valore di OPTIND è $OPTIND" echo "*** *** ***" ;; g ) echo "Passata l'opzione: -$option" echo "Ha un parametro associato, quindi OPTARG=$OPTARG" echo "Il valore di OPTIND è $OPTIND" echo "*** *** ***" ;; \?) echo "Termino" exit 1 ;; * ) echo "Opzione non ancora implementata: -$option" echo "*** *** ***" ;; esac done shift $((OPTIND -1)) echo "Rimangono da analizzare i parametri: $@"
Alcuni esempi dell'output generato da questo script sono:
Modalità sileziosa
#!/usr/bin/env bash while getopts ":vg:uf:" option; do case $option in v ) echo "Passata l'opzione: -$option" echo "Non ha un parametro associato, quindi OPTARG=$OPTARG" echo "Il valore di OPTIND è $OPTIND" echo "*** *** ***" ;; g ) echo "Passata l'opzione: -$option" echo "Ha un parametro associato, quindi OPTARG=$OPTARG" echo "Il valore di OPTIND è $OPTIND" echo "*** *** ***" ;; \?) echo "Opzione non valida: -$OPTARG" >&2 echo "Il valore di OPTIND è $OPTIND" >&2 echo "*** *** ***" exit 1 ;; : ) echo "L'opzione: -$OPTARG richede un parametro, che non è stato passato" >&2 echo "Il valore di OPTIND è $OPTIND" >&2 echo "*** *** ***" exit 1 ;; * ) echo "Opzione non ancora implementata: -$option" >&2 exit 1 esac done shift $((OPTIND -1)) echo "Rimangono da analizzare i parametri: $@"
Alcuni esempi dell'output generato da questo script sono:
Considerazioni sugli esempi d'uso
- In entrambe le modalità, lo script si aspetta di trovare, tra i parametri posizionali, le opzioni 'v' e 'u' senza parametro associato e le opzioni 'g' ed 'f' con un parametro associato.
Nella versione verbosa, il caso \?) gestisce sia un'opzione non valida sia l'assenza di un parametro obbligatorio. La stampa dell'errore è gestita direttamente dal comando getopts, che però continua il parsing. Se si desidera che il programma termini la sua esecuzione in questi due casi, deve essere richiesto esplicitamente, ad esempio con il comando exit.
- Nella versione silenziosa, il caso \?) gestisce un'opzione non valida e il caso : ) l'assenza di un parametro obbligatorio.
- Il caso * ) permette di gestire eventuali opzioni non ancora implementate all'interno dello script. Nei due esempi, le opzioni non ancora implementate sono 'u' ed 'f'.
L'istruzione shift successiva al ciclo while ha lo scopo di eliminare dalla stringa dei parametri posizionali quelli che sono già stati analizzati con getopts. In questo modo, lo script è in grado di gestire successivamente anche eventuali ulteriori parametri posizionali.