Wiki Ubuntu-it

Indice
Partecipa
FAQ
Wiki Blog
------------------
Ubuntu-it.org
Forum
Chiedi
Chat
Cerca
Planet
  • Pagina non alterabile
  • Informazioni
  • Allegati
  • Differenze per "leon-wells/ParsingDellaRigaDiComando"
Differenze tra le versioni 85 e 153 (in 68 versioni)
Versione 85 del 21/11/2021 02.30.57
Dimensione: 23666
Autore: leon-wells
Commento:
Versione 153 del 10/12/2021 18.57.21
Dimensione: 27721
Autore: leon-wells
Commento:
Le cancellazioni sono segnalate in questo modo. Le aggiunte sono segnalate in questo modo.
Linea 6: Linea 6:
<<Include(NuoviStrumentiWiki/PaginaDiProva)>>
Linea 7: Linea 8:
<<Informazioni(forum="http://forum.ubuntu-it.org/viewtopic.php?t=511838"; rilasci="16.04 14.04")>> <<Informazioni(forum="http://forum.ubuntu-it.org/viewtopic.php?t=647707")>>
Linea 10: Linea 11:
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.
<<BR>>

Il '''[[https://it.wikipedia.org/wiki/Parsing|parsing]]''' è la procedura con cui un comando, uno script o più genericamente un programma, analizza le istruzioni che l'utente fornisce quando lo chiama usando il [[https://wiki.ubuntu-it.org/AmministrazioneSistema/Terminale|terminale]].

Queste istruzioni sono una opportuna combinazione di opzioni e parametri e modificano il comportamento del programma a cui vengono passate.

A esempio, per lanciare il comando '''ls''' da terminale una sinossi comune è la seguente:{{{
ls -a -l --color=auto file
}}}


Ul generico comando è composto dal nome del comando stesso seguito da una serie di argomenti detti ''parametri posizionali''.<<BR>>
Linea 20: Linea 23:
 * una '''opzione''' è un argomento, generalmente incluso nella documentazione del comando, la cui presenza modifica il comportamento del comando stesso.<<BR>> 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').<<BR>>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).
  * '''opzioni corte''': consistono in un trattino seguito da una singola lettera (ad esempio `-a` nel comando precedente). Se vi sono più opzioni corte, le si può raggruppate insieme (ad esempio `-al` nel comando precedente).
  * '''opzioni lunghe''': possono essere espresse nello ''stile '''[[https://it.wikipedia.org/wiki/GNU|Gnu]]''''', consistente in due trattini seguiti dal nome completo dell'opzione (as esempio `--color` nel comando precedente), oppure nello ''stile '''[[https://it.wikipedia.org/wiki/XFree86|XF86]]''''', che prevede un singolo trattino seguito dal nome completo dell'opzione.
  * '''parametri''': specificano le azioni che devono svolgere le opzioni e vengono scritti subito dopo di esse. Generalmente, per le opzioni corte sono scritti direttamente attaccati all'opzione o separatati da uno spazio; per le opzioni lunghe sono separati da uno spazio o dal carattere «`=`» (ad esempio , `=auto` nel comando precedente).


Il comando precedente è equivalente al seguente:{{{
ls --color=auto -la file
}}}
In questo caso tutte le opzioni corte sono state riunite ed è stato cambiato l'ordine delle opzioni.

{{{#!wiki important
Non tutti i comandi accettano un ordine casuale delle opzioni.
}}}

La difficoltà del ''parsing'' è proprio nel riconoscimento delle varie opzioni e parametri, a prescindere dalla loro posizione nella sintassi della chiamata.

Per agevolare questa procedura, sono disponibili due utili comandi da usare nel terminale:
 * '''getopt''': ## concisa descrizione del comando
 * '''getopts''': ## concisa descrizione del comando

## Importante, dattilografa due righe per differenziarne l'uso, o su quale usare di volta in volta.

<<Anchor(getopt)>>
Linea 34: Linea 48:
'''getopt''' analizza una stringa di parametri e ne restituisce una versione ''canonica'', ossia una versione standardizzata che potrà poi essere analizzata più facilmente. Generalmente, questa analisi successiva viene eseguita in un ciclo ''while'', all'interno del quale si esegue un'analisi delle casistiche possibili tramite costrutto ''case''. '''getopt''' analizza una stringa di parametri e ne restituisce una versione ''canonica'' e ''standardizzata'' che può essere analizzata più facilmente. Questa analisi successiva viene eseguita in un [[http://www.pluto.it/files/ildp/guide/abs/loops.html#WHILELOOPREF|ciclo while]], all'interno del quale le varie scelte sono effettuate in un [[http://www.pluto.it/files/ildp/guide/abs/testbranch.html|costrutto case]].
Linea 37: Linea 51:
 * Supporta sia le opzioni corte, sia quelle lunghe. Di quest'ultime, supporta sia lo '''''stile GNU''''', sia lo '''''stile XF86'''''.
 * È in grado di gestire opzioni con parametri che siano obbligatori o facoltativi. 

* Supporta sia le opzioni corte, sia quelle lunghe. Di quest'ultime, supporta sia lo ''stile GNU'', sia lo ''stile XF86''.

 * È in grado di gestire opzioni con parametri che siano obbligatori o facoltativi.
Linea 40: Linea 57:
 * La versione descritta in questa guida non è un built-in della shell, ma è inclusa nel pacchetto ''util-linux'' e precedentemente nella ''glibc'' (cioè, la ''GNU lib c''). Ciononostante, può essere facilmente installata nelle distribuzioni in cui non sia presente di default. È disponibile anche per Inoltre, il comando
 {{{
getopt --test
}}} restituisce un ''exit code'' uguale a 4, se la versione installata è quella descritta in questa guida, e può quindi essere usato per un test preliminare all'interno dello script.
 * La versione descritta in questa guida non è un built-in della shell, ma è inclusa nel pacchetto ''util-linux'' e precedentemente nella libreria ''glibc'' (cioè, la ''GNU lib c''). Questa versione è presente di default in Ubuntu e in tutte le derivate ufficiali. Nelle versioni di ''Linux'' in cui non fosse presente, può essere facilmente installata.<<BR>>
 Per verificare che la versione nel proprio sistema sia quella descritta in questa guida, si può controllare che l'output del seguente comando sia uguale a 4:{{{
getopt --test || echo $?}}}
Linea 45: Linea 61:
== Funzionamento ==
Il comando ''getopt'' può essere chiamato con tre diverse sintassi. La più semplice è:
{{{
== Sintassi ==

'
''getopt''' può essere chiamato con tre diverse sintassi:
 *
La sintassi minimale è:
 {{{
Linea 50: Linea 68:
La stringa '''optsting''' elenca le opzioni nel formato corto che il comando può incontrare durante il parsing. Questa stringa può essere racchiusa tra doppi apici. Al suo interno i nomi delle opzioni possono essere elencati senza separatori. Se il carattere che indica l'opzione è seguito dai due punti, l'opzione prevede un parametro obbligatorio; se è seguito da una coppia di doppi punti, il parametro è opzionale. '''parameters''' è la stringa degli argomenti su cui operare. Generalmente si pone uguale alla stringa 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
{{{
 La stringa '''optstring''' elenca le opzioni nel formato corto che si possono incontrare durante il parsing. Questa stringa può essere racchiusa tra doppi apici e al suo interno i nomi delle opzioni possono essere elencati senza separatori. Se l'opzione prevede un parametro obbligatorio, il carattere che la indica è seguito dai due punti; se il parametro è opzionale, è seguito da una coppia di doppi punti.<<BR>>
 La stringa '''parameters''' contiene gli argomenti su cui operare. Generalmente si pone uguale alla stringa dei parametri posizionali passati allo script, cioè "$@". Se si vuole scrivere una stringa alternativa, questa non va racchiusa tra apici, né singoli né doppi.

 * Un'estensione della precedente sintassi è data da:
 {{{
Linea 56: Linea 75:
e
{{{
 Le parti racchiuse tra parentesi quadre sono opzionali. Se mancano, si riottiene la sintassi precedente.<<BR>>
 La stringa '''options''', descritta in dettaglio nella tabella successiva, contiene una serie di opzioni e rispettivi parametri che modificano il funzionamento del comando.

 * Infine, la sintassi più articolata è data da:
 {{{
Linea 60: Linea 82:
'''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.<<BR>>
La stringa '''options''', che nella seconda sintassi può essere presente in due punti, contiene una serie di opzioni e rispettivi parametri che modificano il funzionamento del comando. Tra queste, le più importanti sono:
 * {{{
-l|--long|--longoptions longopts
}}} L'opzione '-l', o le equivalenti '--long' e '--longoptions', indicano che durante il parsing si potranno incontrare opzioni lunghe, i cui nomi vengono specificati nella stringa '''longopts'''. Questa stringa può essere racchiusa tra doppi apici e i nomi al suo interno vanno separati con una virgola. Inoltre, se il nome che indica l'opzione lunga è seguito dai due punti, questa accetta un parametro obbligatorio; se è seguito da una coppia di doppi punti, accetta un parametro facoltativo.
 * {{{
-a|--alternative
}}} Vengono riconosciute le opzioni lunghe nello '''''stile XF86''''', quindi con un singolo trattino iniziale.
 * {{{
-n|--name progname
}}} Imposta il nome dello script al contenuto della variabile ''progname''.
 * {{{
-q|--quiet
}}} L'output degli errori da parte di ''getopt'' è disabilitato.
 * {{{
-Q|--quiet-output
}}} Non viene prodotto l'output di ''getopt'', ovvero la stringa normalizzata dei parametri passati allo script, ma gli errori incontrati nel parsing vengono ancora riportati.
 In questo caso la stringa '''options''' tra parentesi quadre può ricorrere due volte.<<BR>>
 La stringa '''-o|--options''' indica che le opzioni a sinistra e destra della barra verticale sono equivalenti.<<BR>>
 La stringa '''optstring''' ha lo stesso significato visto nelle precedenti sintassi.

Le opzioni e rispettivi parametri che possono essere presenti nella stringa '''options''' tra parentesi quadre sono i seguenti:
||<tablestyle="width:100%;" rowstyle="background-color: #cccccc;" :40%>'''Opzione''' ||<:60%>'''Descrizione''' ||
||<#f7f7f7> '''-l|--long|--longoptions longopts''' || Indica che durante il parsing si potranno incontrare opzioni lunghe, i cui nomi vengono specificati nella stringa '''longopts'''. Questa stringa può essere racchiusa tra doppi apici e i nomi al suo interno vanno separati con una virgola. Se il nome che indica l'opzione lunga è seguito dai due punti, questa accetta un parametro obbligatorio; se è seguito da una coppia di doppi punti, accetta un parametro facoltativo. ||
||<#f7f7f7> '''-a|--alternative''' || Abilita il riconoscimento delle opzioni lunghe nello ''stile XF86'', quindi con un singolo trattino iniziale. ||
||<#f7f7f7> '''-n|--name progname''' || Imposta il nome dello script al contenuto della variabile ''progname''. ||
||<#f7f7f7> '''-q|--quiet''' || Disabilita l'output automatico degli errori. ||
||<#f7f7f7> '''-Q|--quiet-output''' || Disabilita la produzione della stringa normalizzata dei parametri passati allo script, ma gli errori incontrati nel parsing vengono ancora riportati. ||
Linea 80: Linea 95:
I seguenti esempi d'uso mostrano come chiamare ''getopt'' facendo riferimento, rispettivamente, alle tre sintassi viste:
 * {{{

I seguenti esempi mostrano come utilizzare le tre sintassi viste nel paragrafo precedente:

 * Un esempio di invocazione del comando secondo la sintassi minimale è:
 {{{
Linea 83: Linea 101:
}}} Con questa chiamata, ''getopt'' potrà accettare l'opzione 'h' senza parametro, l'opzione 'f' con un parametro obbligatorio e l'opzione 'd' con un parametro facoltativo.
 * {{{
}}}
 Con questa sintassi vengono accettate le seguenti opzioni: '''h''' senza parametro, '''f''' con un parametro obbligatorio e '''d''' con un parametro facoltativo.

 * Un esempio di invocazione del comando con la seconda sintassi è:
 {{{
Linea 86: Linea 107:
}}} Ora, ''getopt'' accetta anche le opzioni nella versione lunga: 'help' senza parametro, 'file' con un parametro obbligatorio e 'dir' con un parametro facoltativo.
 * {{{
getopt -l "help,file:dir::" -o "hf:d::" -a -- "$@"
}}} Qui ''getopt'' accetta le stesse opzioni del caso precedente, ma queste possono essere indicate anche nello ''stile XF86''.

È importante sottolineare che, negli argomenti passati allo script, opzioni e relativi parametri rispettano le seguenti regole:
 * Se un'opzione corta accetta un parametro obbligatorio, opzione e parametro possono essere scritti attaccati o separati da uno spazio. Se il parametro è facoltativo, devono essere scritti attaccati.

 * Se un'opzione lunga accetta un parametro obbligatorio, opzione e parametro possono solo essere separati da uno spazio o dal carattere '='. Se il parametro è obbligatorio, devono essere separati dal carattere '='.
}}}
 Con questa sintassi vengono accettate anche le opzioni nella versione lunga: '''help''' senza parametro
, '''file''' con un parametro obbligatorio e '''dir''' con un parametro facoltativo.

* Un esempio di invocazione del comando seguendo la sintassi più articolata è:
{{{
getopt -l "help,file:,dir::" -o "hf:d::" --alternative -- "$@"
}}}
 Analogo all'esempio precedente, ma con questa sintassi l
e opzioni possono essere indicate anche nello ''stile XF86''.

È importante sottolineare che, negli argomenti passati allo script, le opzioni e i relativi parametri rispettano le seguenti regole:
 * Se un'opzione corta accetta un parametro obbligatorio, opzione e parametro possono essere scritti attaccati o separati da uno spazio.<<BR>>Se il parametro è facoltativo, devono essere scritti attaccati.

 * Se un'opzione lunga accetta un parametro obbligatorio, opzione e parametro devono essere separati da uno spazio o dal carattere «=».<<BR>>Se il parametro è facoltativo, devono essere separati dal carattere «=».
Linea 98: Linea 123:
 * ''getopt'' riconosce qualsiasi abbreviazione non ambigua delle opzioni nel formato lungo. Facendo riferimento agli esempi precedenti, l'opzione '--fi' sarà quindi riconosciuta come ''--file'' nel caso non ci sia rischio di ambiguità con altre opzioni.  * '''getopt''' riconosce qualsiasi abbreviazione non ambigua delle opzioni nel formato lungo. Facendo riferimento agli esempi precedenti, l'opzione `--fi` sarà quindi riconosciuta come `--file` poiché non c'è rischio di ambiguità con altre opzioni.
Linea 101: Linea 126:
Lo script che segue accetta l'opzione 'a' senza parametro, l'opzione 'b' con parametro obbligatorio e l'opzione 'c' con parametro facoltativo. Sono accettate anche le rispettive varianti lunghe 'a-lunga', 'b-lunga' e 'c-lunga' nello ''stile Gnu'' (con due trattini come prefisso).
Lo script che segue accetta l'opzione '''-a''' senza parametro, l'opzione '''-b''' con parametro obbligatorio e l'opzione '''-c''' con parametro facoltativo. Sono accettate anche le rispettive varianti lunghe nello ''stile Gnu'' (ovvero precedute da due trattini) '''--a-lunga''', '''--b-lunga''' e '''--c-lunga'''.
Linea 115: Linea 141:
TEMP=$(getopt --options=$OPZIONI_CORTE --longoptions=$OPZIONI_LUNGHE --name "script_di_prova.sh" -- "$@") TEMP=$(getopt --options="$OPZIONI_CORTE" --longoptions="$OPZIONI_LUNGHE" --name "prova_getopt.sh" -- "$@")
Linea 163: Linea 189:
        echo "--> '"$i"'"         echo "--> '$i'"
Linea 167: Linea 193:
Supponendo di aver salvato lo script con il nome '''script_di_prova_getopt.sh''', di seguito viene mostrata una lista di differenti modi di chiamarlo e alcuni dei rispettivi output prodotti:
 * {{{
$ ./script_di_prova_getopt.sh foo -a bar

Supponendo di aver salvato lo script con il nome `prova_getopt.sh`, di seguito vengono mostrati due differenti modi di chiamarlo e i rispettivi output prodotti:
 * Opzione '''-a''' più due argomenti:{{{
$ ./prova_getopt.sh foo -a bar
Linea 175: Linea 202:
}}} L'argomento 'foo' non viene associato all'opzione 'a', ma interpretato come argomento a se stante ed elencato inseme a 'bar' tra gli argomenti rimanenti dopo il parsing.

 * {{{
$ ./script_di_prova_getopt.sh -b 5 bar foo
}}}
 Il parametro `bar` non viene associato all'opzione '''-a''', in quanto questa opzione non accetta parametri. Viene invece interpretato come argomento a sé stante ed elencato inseme a `foo` tra gli argomenti rimanenti dopo il parsing.

 * Opzione '''-b''' con parametro, più due argomenti::{{{
$ ./prova_getopt.sh -b 5 bar foo
Linea 184: Linea 212:
}}} Per 'foo' e 'bar' si ha lo stesso comportamento del comando precedente, mentre l'argomento '5' viene associato all'opzione '-b'. Visto che per questa opzione il parametro è obbligatorio, si può usare la sintassi equivalente '-b5'.

 * I due esempi precedenti possono essere sintetizzati nel comando:
 {{{
$ ./script_di_prova_getopt.sh -ab 5 foo bar
}}}
 Per `foo` e `bar` si ha lo stesso comportamento del comando precedente. L'argomento `5` invece viene interpretato come parametro dell'opzione '''-b'''. Visto che per questa opzione il parametro è obbligatorio, si può usare la sintassi equivalente `-b5`.

== Considerazioni sull'esempio d'uso ==

 * I due modi di chiamare lo script d'esempio illustrati nel paragrafo precedente possono essere accorpati come segue:{{{
$ ./prova_getopt.sh -ab5 foo bar
Linea 195: Linea 225:
}}} in cui, di nuovo, '-b' e '5' possono essere scritti attaccati.

 * La posizione dei parametri passati allo script può variare, quindi il precedente comando è equivalente a
 
{{{
$ ./script_di_prova_getopt.sh foo -b5 bar -a
}}}

 * La posizione dei parametri passati allo script può variare secondo tutte le combinazioni consistenti con la sintassi descritta precedentemente, ad esempio:{{{
$ ./prova_getopt.sh foo -b5 bar -a
Linea 206: Linea 235:
}}} e a tutte le altre combinazioni consistenti con la sintassi descritta precedentemente.

 * Qualora si volesse usare la versione lunga dell'opzione con parametro obbligatorio, le due sintassi equivalenti sarebbero
 {{{
$ ./script_di_prova_getopt.sh --b-lunga 5
 }}} e

 {{{
$ ./script_di_prova_getopt.sh --b-lunga=5
}}}

 * Per l'opzione corta '-c', che accetta un parametro opzionale, l'unica sintassi valida per passare il parametro è quella in cui i due vengono scritti attaccati
 {{{
$ ./script_di_prova_getopt.sh -c6
}}}

 * Nel caso dell'opzione lunga '--c-lunga', i due sono separati dal carattere '='
 {{{
$ ./script_di_prova_getopt.sh --c-lunga=6
}}}

=== Considerazioni sull'esempio d'uso ===
 * La riga
 {{{
echo "Versione canonica dei parametri prodotta da getopt: "$TEMP" "
}}} visualizza la riorganizzazione dei parametri nella versione canonica prodotta da ''getopt'', ma ai fini del funzionamento dello script è superflua.

 * L'istruzione{{{
eval set -- "$TEMP"
}}} sostituisce i parametri posizionali passati allo script con la stringa '''TEMP''', che è la loro versione ''canonica''. In alcuni script è possibile che manchi l'istruzione ''eval''. In questo caso, sono script non portabili pensati per BSD. La versione in cui è presente anche ''eval'' risulta portabile. Infine, le doppie virgolette che racchiudono ''$TEMP'' sono fondamentali.

 * Il comando '''shift''' viene utilizzato all'interno del costrutto ''case'' per avanzare nella lettura dei parametri posizionali passati allo script. Nel caso di un'opzione senza parametro, si ''shifta'' di una posizione; nel caso dei due trattini '--' si ''shifta'' di una posizione e si interrompe il parsing; nel caso di una opzione con parametro facoltativo, si ''shifta'' di due posizioni.

 * Il costrutto ''case'' nidificato è un esempio di come si gestisce un'opzione che abbia un parametro facoltativo.
}}}

 * L'opzione con parametro obbligatorio '''-b''' ha due sintassi equivalenti in versione lunga:{{{
$ ./prova_getopt.sh --b-lunga 5
}}}{{{
$ ./prova_getopt.sh --b-lunga=5
}}}

 * L'unica sintassi valida per l'opzione corta '''-c''', che accetta un parametro opzionale, è quella in cui opzione e parametro sono scritti attaccati:{{{
$ ./prova_getopt.sh -c6
}}}

 * La sintassi equivalente dell'opzione '''-c''' in versione lunga richiede che opzione e parametro siano separati dal carattere «`=`»:{{{
$ ./prova_getopt.sh --c-lunga=6
}}}

 * Se si vogliono passare parametri posizionali interpretabili come opzioni, questi vanno scritti dopo i doppi trattini:
 {{{
$ ./prova_getopt.sh foo -ab5 -- -car -bar -6
Versione canonica dei parametri prodotta da getopt: -a -b '5' -- 'foo' '-car' '-bar' '-6'
Opzione '-a', senza argomento.
Opzione '-b', con argomento '5'.
Argomenti rimanenti:
--> 'foo'
--> '-car'
--> '-bar'
--> '-6'
}}}
 Senza il doppio trattino, infatti, `-6` verrebbe interpretata come opzione non permessa, mentre `-car` e `-bar` rispettivamente come opzioni '''-c''' e '''-b''', entrambe con `ar` come parametro.

 * La porzione di codice:{{{
getopt --test > /dev/null
if [[ $? -ne 4 ]]; then
    echo "La versione di getopt non è quella del pacchetto utils-linux"
    exit 1
fi}}} serve per verificare che la versione di '''getopt''' sia quella descritta in questa guida. È superflua per Ubuntu e le sue derivate, ma permette di verificare che lo script sia correttamente utilizzabile anche in altre generiche distribuzioni di ''Linux''.

 * La riga seguente visualizza la riorganizzazione dei parametri nella versione canonica prodotta da '''getopt''':{{{
echo "Versione canonica dei parametri prodotta da getopt: "$TEMP" "}}}
 Ai fini del funzionamento dello script è superflua.

 * L'istruzione seguente sostituisce i parametri posizionali passati allo script con la stringa `TEMP`, che è la loro versione ''canonica'':{{{
eval set -- "$TEMP"`}}}
 In alcuni script è possibile che manchi l'istruzione '''eval'''. In questo caso, sono script non portabili pensati per [[https://it.wikipedia.org/wiki/Berkeley_Software_Distribution|BSD]]. La versione in cui è presente anche '''eval''' risulta portabile e deve essere preferita. Infine, le doppie virgolette che racchiudono `$TEMP` sono fondamentali.

 * Il comando '''shift''' viene utilizzato all'interno del costrutto ''case'' per avanzare nella lettura dei parametri posizionali passati allo script. Questo comando ha l'effetto di far slittare verso sinistra i parametri posizionali, eliminandoli:
  * Nel caso di un'opzione senza parametro, si slitta di una posizione.
  * Nel caso dei due trattini `--` si slitta di una posizione e si interrompe il parsing.
  * Nel caso di una opzione con parametro facoltativo, si slitta di due posizioni.

 * Il costrutto ''case'' nidificato è un esempio di come si gestisce un'opzione che ha un parametro facoltativo.

<<Anchor(getopts)>>
Linea 245: Linea 292:
 * È un built-in della shell. Questo comporta che:  * È un built-in della shell, quindi:
Linea 247: Linea 294:
   * 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.
   * 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.
Linea 253: Linea 300:
 * È 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.  * Può 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.
Linea 257: Linea 304:
Linea 263: Linea 311:
||<:> 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 queste ultime, 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 è che nel seconda modalità produrrà dei messaggi in caso di 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
||<:> '''optstring''' || È una stringa che istruisce il comando 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 facoltativa. Di default, il comando fa il parsing dei parametri posizionali, cioè della stringa $@; se è presente una stringa ''args'', farà il parsing dei parametri contenuti in quest'ultima. ||

'''getopts''' viene quindi istruito sulle opzioni e gli eventuali parametri che si può aspettare tramite '''optstring'''.<<BR>>La sintassi di questa stringa è molto semplice.

 * Ogni opzione che si vuole aggiungere, viene indicata con la relativa lettera. Non sono consentiti i caratteri ':' e '?'.
 * Se l'opzione prevede un parametro associato, il carattere che la indica è seguito dai due punti. Quindi, se si vuole permettere l'opzione 'f' con un parametro associato, nella stringa '''optstring''' si aggiungerà la sequenza 'f:'
 * Il comando ''getopts'' può essere impostato nella modalità silenziosa, usando i due punti ':' come prefisso di ''optstring''. Se questo carattere è assente, ''getopts'' è in modalità verbosa. La differenza è che nel seconda modalità produce messaggi di errori automatici 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.

Quindi, se desideriamo che il comando 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:
Linea 277: Linea 325:
||<:> 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:
||<:> '''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''' || Se è previsto un parametro, viene impostata al valore si quest'ultimo. Se l'opzione non prevede un parametro, è lasciato vuoto. 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 il comando ed è riassunta nella seguente tabella:
Linea 284: Linea 332:
||<20%>opzione<<BR>>non valida ||varname è posto uguale al carattere '?'<<BR>>OPTARG è lasciato vuoto.||
||<20%>parametro obbligatorio<<BR>>non fornito ||varname è posto uguale al carattere '?'<<BR>>OPTARG è lasciato vuoto e viene stampato un messaggio d'errore.||
||<20%>opzione<<BR>>non valida ||'''varname''' è posto uguale al carattere '?'<<BR>>'''OPTARG''' è lasciato vuoto.||
||<20%>parametro obbligatorio<<BR>>non fornito ||'''varname''' è posto uguale al carattere '?'<<BR>>'''OPTARG''' è lasciato vuoto e viene stampato un messaggio d'errore.||
Linea 288: Linea 336:
||<20%>opzione<<BR>>non valida ||varname è posto uguale al carattere '?'<<BR>>OPTARG è posto uguale all'opzione non valida.||
||<20%>parametro obbligatorio<<BR>>non fornito ||varname è posto uguale al carattere ':'<<BR>>OPTARG è posto uguale all'opzione||
||<20%>opzione<<BR>>non valida ||'''varname''' è posto uguale al carattere '?'<<BR>>'''OPTARG''' è posto uguale all'opzione non valida.||
||<20%>parametro obbligatorio<<BR>>non fornito ||'''varname''' è posto uguale al carattere ':'<<BR>>'''OPTARG''' è posto uguale all'opzione||
Linea 294: Linea 342:
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 '--'. Il comando viene generalmente usato all'interno di un ciclo ''while'': a ogni iterazione, legge dalla stringa dei parametri posizionali (o da ''args'' se fornito) un'opzione e il suo eventuale parametro; se tutto è corretto, aggiorna le sue variabili interne, secondo quanto visto al punto precedente, e fornisce questi dati all'utente per la loro analisi, che viene svolta all'interno di un costrutto ''case''. Il comando restituisce un ''exit status'' uguale a 1, interrompendo il ciclo ''while'', quando incontra il primo parametro opzionale che non corrisponde a una opzione prevista.
Linea 298: Linea 346:

Lo script che segue è un esempio di utilizzo del comando nella modalità verbosa. Lo script accetta le opzioni 'a' e 'c' senza parametro e le opzioni 'b' e 'd' con un parametro. Le opzioni 'b' e 'd' non sono implementate, per simulare una situazione frequente nelle fasi iniziali di sviluppo di uno script.
Linea 302: Linea 352:
while getopts "ab:cd:" option; while getopts "ab:cd:" option
Linea 307: Linea 357:
            #~ echo "Passata l'opzione: -$option"
            #~ echo "Non ha un parametro associato, quindi OPTARG=$OPTARG"
            echo "Il valore di OPTIND è $OPTIND"
            echo "OPTIND è $OPTIND"
Linea 314: Linea 362:
            #~ echo "Passata l'opzione: -$option"
            #~ echo "Ha un parametro associato, quindi OPTARG=$OPTARG"
            echo "Il valore di OPTIND è $OPTIND"
            echo "OPTIND è $OPTIND"
Linea 320: Linea 366:
            echo "Termino"
            echo "Il valore di OPTIND è $OPTIND"
            echo "OPTIND è $OPTIND" >&2
            echo "Termino" >&2
Linea 326: Linea 372:
            echo "Il valore di OPTIND è $OPTIND"             echo "OPTIND è $OPTIND"
Linea 331: Linea 377:
Linea 338: Linea 385:
        echo "--> '"$i"'"         echo "--> '$i'"
Linea 342: Linea 389:
Alcuni esempi dell'output generato da questo script sono:
 * {{{
foo
}}}

 * {{{
foo
}}}

 * {{{
foo
}}}

 * {{{
foo

Supponendo di aver salvato lo script con il nome `prova_getopts_verboso.sh`, alcuni esempi dell'output generato da questo script sono:
 {{{
$ ./prova_getopts_verboso.sh -a
Opzione -a, senza argomento
*** *** ***
Il valore di OPTIND è 2
}}} in cui allo script è fornita solo l'opzione 'a'.

 {{{
$ ./prova_getopts_verboso.sh -ab 10
Opzione -a, senza argomento
OPTIND è 1
*** *** ***
Opzione -b, con argomento '10'
OPTIND è 3
*** *** ***
}}} in cui è fornita anche l'opzione 'b' con il parametro '10'.

 * L'ordine delle opzioni può essere cambiato in modo consistente con la sintassi, quindi il comando precedente equivale a:
 {{{
$ ./prova_getopts_verboso.sh -b 10 -a
Opzione -b, con argomento '10'
OPTIND è 3
*** *** ***
Opzione -a, senza argomento
OPTIND è 4
*** *** ***
}}}

 {{{
$ ./prova_getopts_verboso.sh -d 10 -a
Opzione non ancora implementata: -d
OPTIND è 3
*** *** ***
Opzione -a, senza argomento
OPTIND è 4
*** *** ***
}}} in cui viene passata l'opzione non implementata '-d' con il parametro '10'

 * Infine, se si passa un'opzione non valida, getopts produce automaticamente un messaggio d'errore:
 {{{
$ ./prova_getopts_verboso.sh -f
./prova_getopts_verboso.sh: opzione illecita -- f
OPTIND è 2
Termino
Linea 361: Linea 439:

Lo script seguente è l'analogo del precedente, ma in modalità silenziosa:
Linea 370: Linea 450:
            #~ echo "Passata l'opzione: -$option"
            #~ echo "Non ha un parametro associato, quindi OPTARG=$OPTARG"
            echo "Il valore di OPTIND è $OPTIND"
            echo "OPTIND è $OPTIND"
Linea 377: Linea 455:
            #~ echo "Passata l'opzione: -$option"
            #~ echo "Ha un parametro associato, quindi OPTARG=$OPTARG"
            echo "Il valore di OPTIND è $OPTIND"
            echo "OPTIND è $OPTIND"
Linea 384: Linea 460:
            echo "Il valore di OPTIND è $OPTIND" >&2             echo "OPTIND è $OPTIND" >&2
            echo "Termino" >&2
            exit 1
            ;;
        : )
            echo "-$OPTARG richede un parametro, che non è stato passato" >&2
            echo "OPTIND è $OPTIND" >&2
            echo "Termino" >&2
            exit 1
            ;;
        *)
            echo "Opzione non ancora implementata: -$option"
            echo "OPTIND è $OPTIND"
Linea 386: Linea 474:
            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
Linea 407: Linea 484:
        echo "--> '"$i"'"         echo "--> '$i'"
Linea 411: Linea 488:
Alcuni esempi dell'output generato da questo script sono:

 * {{{
foo
}}}

 * {{{
foo
}}}

 * {{{
foo
}}}

 * {{{
foo
}}}


=== Considerazioni sugli esempi d'uso ===

 * In entrambe le modalità, durante il parsing lo script si aspetta di trovare 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 continua il parsing dopo aver comunicato l'errore. 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'. Questa modalità risulta molto comoda nella fase di implementazione.
 * 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''. Il parametro ''OPTIND'' assicura infatti di ottenere lo ''shift'' di tutti i parametri già letti. In questo modo, lo script è in grado di gestire successivamente anche eventuali ulteriori parametri posizionali.
Differenze dallo script precedente ci sono solo per opzioni non valide e parametri obbligatori non passati. Se lo script è stato salvato col nome `prova_getopts_silenzioso.sh`, si ha rispettivamente:
 {{{
$ ./prova_getopts_silenzioso.sh -f
Opzione non valida: -f
OPTIND è 2
Termino
}}}

 {{{
$ ./prova_getopts_silenzioso.sh -b
-b richede un parametro, che non è stato passato
OPTIND è 2
Termino
}}}


== Considerazioni sugli esempi d'uso ==

 * '''getopts''' restituisce un ''exit status'' pari a 1 se incontra un parametro che non corrisponde a una opzione prevista. Per gli script in questi esempi, è quindi necessario scrivere per ultimi i parametri che si vogliono analizzare a valle del ciclo ''while''. Se questi sono interpretabili come opzioni, vanno separati da un doppio trattino. In realtà, è possibile una gestione più articolata di questa tipologia di parametri, che però esula dalle finalità di questa guida introduttiva e per la quale si rimanda alla [[https://forum.ubuntu-it.org/viewforum.php?f=33|sezione programmazione del forum]].

 * 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 continua il parsing dopo aver comunicato l'errore. 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 'b' e 'd'. Questa modalità risulta molto comoda nella fase iniziale di implementazione di uno script.

 * L'istruzione '''shift''' successiva al ciclo ''while'' ha lo scopo di eliminare dalla stringa dei parametri posizionali quelli che sono già stati analizzati. Il parametro '''OPTIND''' assicura infatti di ottenere lo slittamento verso sinistra di tutti i parametri già letti. In questo modo, lo script è in grado di gestire successivamente anche eventuali ulteriori parametri posizionali.

 * È utile ricordare che '''OPTIND''' contiene l'indice del parametro posizionale del prossimo argomento da processare e quindi non viene incrementato fino ad aver esaurito l'analisi di tutte le opzioni scritte attaccate.
Linea 440: Linea 520:
 * [[http://www.gnu.org/software/bash/manual/bash.html|Manuale ufficiale di Bash]]
 * [[http://www.tldp.org/LDP/abs/html/|Guida avanzata di scripting Bash]]
 * [[http://www.pluto.it/files/ildp/guide/abs/index.html|Guida avanzata di scripting Bash in italiano]]


Attenzione! Questa è una Pagina di prova. Le informazioni riportate potrebbero essere incomplete, errate e potenzialmente pericolose. Per contribuire alla realizzazione di questa pagina consultare la discussione di riferimento.

Problemi in questa pagina? Segnalali in questa discussione

Introduzione

Il parsing è la procedura con cui un comando, uno script o più genericamente un programma, analizza le istruzioni che l'utente fornisce quando lo chiama usando il terminale.

Queste istruzioni sono una opportuna combinazione di opzioni e parametri e modificano il comportamento del programma a cui vengono passate.

A esempio, per lanciare il comando ls da terminale una sinossi comune è la seguente:

ls -a -l --color=auto file

Ul generico comando è composto dal nome del comando stesso seguito da una serie di argomenti detti parametri posizionali.
Questi ultimi possono essere suddivisi in alcune categorie logiche:

  • opzioni corte: consistono in un trattino seguito da una singola lettera (ad esempio -a nel comando precedente). Se vi sono più opzioni corte, le si può raggruppate insieme (ad esempio -al nel comando precedente).

  • opzioni lunghe: possono essere espresse nello stile Gnu, consistente in due trattini seguiti dal nome completo dell'opzione (as esempio --color nel comando precedente), oppure nello stile XF86, che prevede un singolo trattino seguito dal nome completo dell'opzione.

  • parametri: specificano le azioni che devono svolgere le opzioni e vengono scritti subito dopo di esse. Generalmente, per le opzioni corte sono scritti direttamente attaccati all'opzione o separatati da uno spazio; per le opzioni lunghe sono separati da uno spazio o dal carattere «=» (ad esempio , =auto nel comando precedente).

Il comando precedente è equivalente al seguente:

ls --color=auto -la file 

In questo caso tutte le opzioni corte sono state riunite ed è stato cambiato l'ordine delle opzioni.

Non tutti i comandi accettano un ordine casuale delle opzioni.

La difficoltà del parsing è proprio nel riconoscimento delle varie opzioni e parametri, a prescindere dalla loro posizione nella sintassi della chiamata.

Per agevolare questa procedura, sono disponibili due utili comandi da usare nel terminale:

  • getopt: ## concisa descrizione del comando

  • getopts: ## concisa descrizione del comando

getopt

getopt analizza una stringa di parametri e ne restituisce una versione canonica e standardizzata che può essere analizzata più facilmente. Questa analisi successiva viene eseguita in un ciclo while, all'interno del quale le varie scelte sono effettuate in un costrutto case.

Pro

  • Supporta sia le opzioni corte, sia quelle lunghe. Di quest'ultime, supporta sia lo stile GNU, sia lo stile XF86.

  • È in grado di gestire opzioni con parametri che siano obbligatori o facoltativi.

Contro

  • La versione descritta in questa guida non è un built-in della shell, ma è inclusa nel pacchetto util-linux e precedentemente nella libreria glibc (cioè, la GNU lib c). Questa versione è presente di default in Ubuntu e in tutte le derivate ufficiali. Nelle versioni di Linux in cui non fosse presente, può essere facilmente installata.
    Per verificare che la versione nel proprio sistema sia quella descritta in questa guida, si può controllare che l'output del seguente comando sia uguale a 4:

    getopt --test || echo $?

Sintassi

getopt può essere chiamato con tre diverse sintassi:

  • La sintassi minimale è:
    getopt optstring parameters

    La stringa optstring elenca le opzioni nel formato corto che si possono incontrare durante il parsing. Questa stringa può essere racchiusa tra doppi apici e al suo interno i nomi delle opzioni possono essere elencati senza separatori. Se l'opzione prevede un parametro obbligatorio, il carattere che la indica è seguito dai due punti; se il parametro è opzionale, è seguito da una coppia di doppi punti.
    La stringa parameters contiene gli argomenti su cui operare. Generalmente si pone uguale alla stringa dei parametri posizionali passati allo script, cioè "$@". Se si vuole scrivere una stringa alternativa, questa non va racchiusa tra apici, né singoli né doppi.

  • Un'estensione della precedente sintassi è data da:
    getopt [options] [--] optstring parameters

    Le parti racchiuse tra parentesi quadre sono opzionali. Se mancano, si riottiene la sintassi precedente.
    La stringa options, descritta in dettaglio nella tabella successiva, contiene una serie di opzioni e rispettivi parametri che modificano il funzionamento del comando.

  • Infine, la sintassi più articolata è data da:
    getopt [options] -o|--options optstring [options] [--] parameters

    In questo caso la stringa options tra parentesi quadre può ricorrere due volte.
    La stringa -o|--options indica che le opzioni a sinistra e destra della barra verticale sono equivalenti.
    La stringa optstring ha lo stesso significato visto nelle precedenti sintassi.

Le opzioni e rispettivi parametri che possono essere presenti nella stringa options tra parentesi quadre sono i seguenti:

Opzione

Descrizione

-l|--long|--longoptions longopts

Indica che durante il parsing si potranno incontrare opzioni lunghe, i cui nomi vengono specificati nella stringa longopts. Questa stringa può essere racchiusa tra doppi apici e i nomi al suo interno vanno separati con una virgola. Se il nome che indica l'opzione lunga è seguito dai due punti, questa accetta un parametro obbligatorio; se è seguito da una coppia di doppi punti, accetta un parametro facoltativo.

-a|--alternative

Abilita il riconoscimento delle opzioni lunghe nello stile XF86, quindi con un singolo trattino iniziale.

-n|--name progname

Imposta il nome dello script al contenuto della variabile progname.

-q|--quiet

Disabilita l'output automatico degli errori.

-Q|--quiet-output

Disabilita la produzione della stringa normalizzata dei parametri passati allo script, ma gli errori incontrati nel parsing vengono ancora riportati.

Esempi di chiamate al comando

I seguenti esempi mostrano come utilizzare le tre sintassi viste nel paragrafo precedente:

  • Un esempio di invocazione del comando secondo la sintassi minimale è:
    getopt "hf:d::" "$@"

    Con questa sintassi vengono accettate le seguenti opzioni: h senza parametro, f con un parametro obbligatorio e d con un parametro facoltativo.

  • Un esempio di invocazione del comando con la seconda sintassi è:
    getopt -l "help,file:,dir::" -- "hf:d::" "$@"

    Con questa sintassi vengono accettate anche le opzioni nella versione lunga: help senza parametro, file con un parametro obbligatorio e dir con un parametro facoltativo.

  • Un esempio di invocazione del comando seguendo la sintassi più articolata è:
    getopt -l "help,file:,dir::" -o "hf:d::" --alternative -- "$@"

    Analogo all'esempio precedente, ma con questa sintassi le opzioni possono essere indicate anche nello stile XF86.

È importante sottolineare che, negli argomenti passati allo script, le opzioni e i relativi parametri rispettano le seguenti regole:

  • Se un'opzione corta accetta un parametro obbligatorio, opzione e parametro possono essere scritti attaccati o separati da uno spazio.
    Se il parametro è facoltativo, devono essere scritti attaccati.

  • Se un'opzione lunga accetta un parametro obbligatorio, opzione e parametro devono essere separati da uno spazio o dal carattere «=».
    Se il parametro è facoltativo, devono essere separati dal carattere «=».

  • Le opzioni corte possono essere raggruppate e scritte in qualsiasi ordine, con l'accortezza di lasciare accoppiate ai propri parametri quelle che li prevedono.
  • getopt riconosce qualsiasi abbreviazione non ambigua delle opzioni nel formato lungo. Facendo riferimento agli esempi precedenti, l'opzione --fi sarà quindi riconosciuta come --file poiché non c'è rischio di ambiguità con altre opzioni.

Esempio d'uso

Lo script che segue accetta l'opzione -a senza parametro, l'opzione -b con parametro obbligatorio e l'opzione -c con parametro facoltativo. Sono accettate anche le rispettive varianti lunghe nello stile Gnu (ovvero precedute da due trattini) --a-lunga, --b-lunga e --c-lunga.

#! /bin/bash

getopt --test > /dev/null
if [[ $? -ne 4 ]]; then
    echo "La versione di getopt non è quella del pacchetto utils-linux"
    exit 1
fi

OPZIONI_CORTE=ab:c::
OPZIONI_LUNGHE=a-lunga,b-lunga:,c-lunga::

TEMP=$(getopt --options="$OPZIONI_CORTE" --longoptions="$OPZIONI_LUNGHE" --name "prova_getopt.sh" -- "$@")
if [[ $? -ne 0 ]]; then
    echo "getopt ha fallito il parsing"
    exit 2
fi

echo "Versione canonica dei parametri prodotta da getopt: "$TEMP""

eval set -- "$TEMP"

while true
do
    case "$1" in
        -a|--a-lunga) 
            echo "Opzione '$1', senza argomento."
            shift
            ;;
        -b|--b-lunga) 
            echo "Opzione '$1', con argomento '$2'."
            shift 2
            ;;
        -c|--c-lunga)
            case "$2" in
                "") 
                    echo "Opzione '$1', senza argomento."
                    shift 2
                    ;;
                *)  
                    echo "Option c, con argomento '$2'."
                    shift 2
                    ;;
            esac
            ;;
        --) 
            shift
            break
            ;;
        *) 
            echo "Errore interno!"
            exit  ;;
    esac
done

if [[ $# != 0 ]]
then
    echo "Argomenti rimanenti:"
    for i in "$@"
    do
        echo "--> '$i'"
    done
fi

Supponendo di aver salvato lo script con il nome prova_getopt.sh, di seguito vengono mostrati due differenti modi di chiamarlo e i rispettivi output prodotti:

  • Opzione -a più due argomenti:

    $ ./prova_getopt.sh foo -a bar 
    Versione canonica dei parametri prodotta da getopt:  -a -- 'foo' 'bar' 
    Opzione '-a', senza argomento.
    Argomenti rimanenti:
    --> 'foo'
    --> 'bar'

    Il parametro bar non viene associato all'opzione -a, in quanto questa opzione non accetta parametri. Viene invece interpretato come argomento a sé stante ed elencato inseme a foo tra gli argomenti rimanenti dopo il parsing.

  • Opzione -b con parametro, più due argomenti::

    $ ./prova_getopt.sh -b 5 bar foo
    Versione canonica dei parametri prodotta da getopt:  -b '5' -- 'bar' 'foo' 
    Opzione '-b', con argomento '5'.
    Argomenti rimanenti:
    --> 'bar'
    --> 'foo'

    Per foo e bar si ha lo stesso comportamento del comando precedente. L'argomento 5 invece viene interpretato come parametro dell'opzione -b. Visto che per questa opzione il parametro è obbligatorio, si può usare la sintassi equivalente -b5.

Considerazioni sull'esempio d'uso

  • I due modi di chiamare lo script d'esempio illustrati nel paragrafo precedente possono essere accorpati come segue:

    $ ./prova_getopt.sh  -ab5 foo bar
    Versione canonica dei parametri prodotta da getopt:  -a -b '5' -- 'foo' 'bar' 
    Opzione '-a', senza argomento.
    Opzione '-b', con argomento '5'.
    Argomenti rimanenti:
    --> 'foo'
    --> 'bar'
  • La posizione dei parametri passati allo script può variare secondo tutte le combinazioni consistenti con la sintassi descritta precedentemente, ad esempio:

    $ ./prova_getopt.sh  foo -b5 bar -a
    Versione canonica dei parametri prodotta da getopt:  -b '5' -a -- 'foo' 'bar' 
    Opzione '-b', con argomento '5'.
    Opzione '-a', senza argomento.
    Argomenti rimanenti:
    --> 'foo'
    --> 'bar'
  • L'opzione con parametro obbligatorio -b ha due sintassi equivalenti in versione lunga:

    $ ./prova_getopt.sh --b-lunga 5
    $ ./prova_getopt.sh --b-lunga=5
  • L'unica sintassi valida per l'opzione corta -c, che accetta un parametro opzionale, è quella in cui opzione e parametro sono scritti attaccati:

    $ ./prova_getopt.sh -c6
  • La sintassi equivalente dell'opzione -c in versione lunga richiede che opzione e parametro siano separati dal carattere «=»:

    $ ./prova_getopt.sh --c-lunga=6 
  • Se si vogliono passare parametri posizionali interpretabili come opzioni, questi vanno scritti dopo i doppi trattini:
    $ ./prova_getopt.sh  foo -ab5  --  -car -bar -6
    Versione canonica dei parametri prodotta da getopt:  -a -b '5' -- 'foo' '-car' '-bar' '-6' 
    Opzione '-a', senza argomento.
    Opzione '-b', con argomento '5'.
    Argomenti rimanenti:
    --> 'foo'
    --> '-car'
    --> '-bar'
    --> '-6'

    Senza il doppio trattino, infatti, -6 verrebbe interpretata come opzione non permessa, mentre -car e -bar rispettivamente come opzioni -c e -b, entrambe con ar come parametro.

  • La porzione di codice:

    getopt --test > /dev/null
    if [[ $? -ne 4 ]]; then
        echo "La versione di getopt non è quella del pacchetto utils-linux"
        exit 1
    fi

    serve per verificare che la versione di getopt sia quella descritta in questa guida. È superflua per Ubuntu e le sue derivate, ma permette di verificare che lo script sia correttamente utilizzabile anche in altre generiche distribuzioni di Linux.

  • La riga seguente visualizza la riorganizzazione dei parametri nella versione canonica prodotta da getopt:

    echo "Versione canonica dei parametri prodotta da getopt: "$TEMP" "
    Ai fini del funzionamento dello script è superflua.
  • L'istruzione seguente sostituisce i parametri posizionali passati allo script con la stringa TEMP, che è la loro versione canonica:

    eval set -- "$TEMP"`

    In alcuni script è possibile che manchi l'istruzione eval. In questo caso, sono script non portabili pensati per BSD. La versione in cui è presente anche eval risulta portabile e deve essere preferita. Infine, le doppie virgolette che racchiudono $TEMP sono fondamentali.

  • Il comando shift viene utilizzato all'interno del costrutto case per avanzare nella lettura dei parametri posizionali passati allo script. Questo comando ha l'effetto di far slittare verso sinistra i parametri posizionali, eliminandoli:

    • Nel caso di un'opzione senza parametro, si slitta di una posizione.
    • Nel caso dei due trattini -- si slitta di una posizione e si interrompe il parsing.

    • Nel caso di una opzione con parametro facoltativo, si slitta di due posizioni.
  • Il costrutto case nidificato è un esempio di come si gestisce un'opzione che ha un parametro facoltativo.

getopts

Pro

  • È un built-in della shell, quindi:
    • è definito nello standard POSIX e non c'è bisogno di fare attenzione alle sue diverse implementazioni.
    • 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

  • Può 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.

  • Non supporta le opzioni con parametri facoltativi.

Funzionamento

La sintassi del comando è:

getopts optstring varname [args]

in cui

Parametro

Descrizione

optstring

È una stringa che istruisce il comando 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 facoltativa. Di default, il comando fa il parsing dei parametri posizionali, cioè della stringa $@; se è presente una stringa args, farà il parsing dei parametri contenuti in quest'ultima.

getopts viene quindi 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. Non sono consentiti i caratteri ':' e '?'.
  • Se l'opzione prevede un parametro associato, il carattere che la indica è seguito dai due punti. Quindi, se si vuole permettere l'opzione 'f' con un parametro associato, nella stringa optstring si aggiungerà la sequenza 'f:'

  • Il comando getopts può essere impostato nella modalità silenziosa, usando i due punti ':' come prefisso di optstring. Se questo carattere è assente, getopts è in modalità verbosa. La differenza è che nel seconda modalità produce messaggi di errori automatici 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.

Quindi, se desideriamo che il comando 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

Se è previsto un parametro, viene impostata al valore si quest'ultimo. Se l'opzione non prevede un parametro, è lasciato vuoto. 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 il comando ed è riassunta nella seguente tabella:

Modalità verbosa

opzione
non valida

varname è posto uguale al carattere '?'
OPTARG è lasciato vuoto.

parametro obbligatorio
non fornito

varname è posto uguale al carattere '?'
OPTARG è lasciato vuoto e viene stampato un messaggio d'errore.

Modalità silenziosa

opzione
non valida

varname è posto uguale al carattere '?'
OPTARG è posto uguale all'opzione non valida.

parametro obbligatorio
non fornito

varname è posto uguale al carattere ':'
OPTARG è posto uguale all'opzione

Esempi d'uso

Il comando viene generalmente usato all'interno di un ciclo while: a ogni iterazione, legge dalla stringa dei parametri posizionali (o da args se fornito) un'opzione e il suo eventuale parametro; se tutto è corretto, aggiorna le sue variabili interne, secondo quanto visto al punto precedente, e fornisce questi dati all'utente per la loro analisi, che viene svolta all'interno di un costrutto case. Il comando restituisce un exit status uguale a 1, interrompendo il ciclo while, quando incontra il primo parametro opzionale che non corrisponde a una opzione prevista.

Modalità verbosa

Lo script che segue è un esempio di utilizzo del comando nella modalità verbosa. Lo script accetta le opzioni 'a' e 'c' senza parametro e le opzioni 'b' e 'd' con un parametro. Le opzioni 'b' e 'd' non sono implementate, per simulare una situazione frequente nelle fasi iniziali di sviluppo di uno script.

#!/bin/bash

while getopts "ab:cd:" option
do
    case $option in
        a)
            echo "Opzione -$option, senza argomento"
            echo "OPTIND è $OPTIND"
            echo "*** *** ***"
            ;;
        b)
            echo "Opzione -$option, con argomento '"$OPTARG"'"
            echo "OPTIND è $OPTIND"
            echo "*** *** ***"
            ;;
        \?)
            echo "OPTIND è $OPTIND" >&2
            echo "Termino" >&2
            exit 1
            ;;
        *) 
            echo "Opzione non ancora implementata: -$option"
            echo "OPTIND è $OPTIND"
            echo "*** *** ***"
            ;;
    esac
done

shift $((OPTIND - 1))

if [[ $# -ne 0 ]]
then
    echo "Rimangono da analizzare i parametri:"
    for i in "$@"
    do
        echo "--> '$i'"
    done
fi

Supponendo di aver salvato lo script con il nome prova_getopts_verboso.sh, alcuni esempi dell'output generato da questo script sono:

  • $ ./prova_getopts_verboso.sh -a
    Opzione -a, senza argomento
    *** *** ***
    Il valore di OPTIND è 2
    in cui allo script è fornita solo l'opzione 'a'.
    $ ./prova_getopts_verboso.sh -ab 10
    Opzione -a, senza argomento
    OPTIND è 1
    *** *** ***
    Opzione -b, con argomento '10'
    OPTIND è 3
    *** *** ***
    in cui è fornita anche l'opzione 'b' con il parametro '10'.
  • L'ordine delle opzioni può essere cambiato in modo consistente con la sintassi, quindi il comando precedente equivale a:
    $ ./prova_getopts_verboso.sh -b 10 -a
    Opzione -b, con argomento '10'
    OPTIND è 3
    *** *** ***
    Opzione -a, senza argomento
    OPTIND è 4
    *** *** ***
    $ ./prova_getopts_verboso.sh -d 10 -a
    Opzione non ancora implementata: -d
    OPTIND è 3
    *** *** ***
    Opzione -a, senza argomento
    OPTIND è 4
    *** *** ***
    in cui viene passata l'opzione non implementata '-d' con il parametro '10'
  • Infine, se si passa un'opzione non valida, getopts produce automaticamente un messaggio d'errore:
    $ ./prova_getopts_verboso.sh -f
    ./prova_getopts_verboso.sh: opzione illecita -- f
    OPTIND è 2
    Termino

Modalità sileziosa

Lo script seguente è l'analogo del precedente, ma in modalità silenziosa:

#!/usr/bin/env bash

while getopts ":ab:cd:" option;
do
    case $option in
        a)
            echo "Opzione -$option, senza argomento"
            echo "OPTIND è $OPTIND"
            echo "*** *** ***"
            ;;
        b)
            echo "Opzione -$option, con argomento '"$OPTARG"'"
            echo "OPTIND è $OPTIND"
            echo "*** *** ***"
            ;;
        \?)
            echo "Opzione non valida: -$OPTARG" >&2
            echo "OPTIND è $OPTIND" >&2
            echo "Termino" >&2
            exit 1
            ;;
        : )
            echo "-$OPTARG richede un parametro, che non è stato passato" >&2
            echo "OPTIND è $OPTIND" >&2
            echo "Termino" >&2
            exit 1
            ;;
        *)
            echo "Opzione non ancora implementata: -$option"
            echo "OPTIND è $OPTIND"
            echo "*** *** ***"
    esac
done

shift $((OPTIND -1))

if [[ $# -ne 0 ]]
then
    echo "Rimangono da analizzare i parametri:"
    for i in "$@"
    do
        echo "--> '$i'"
    done
fi

Differenze dallo script precedente ci sono solo per opzioni non valide e parametri obbligatori non passati. Se lo script è stato salvato col nome prova_getopts_silenzioso.sh, si ha rispettivamente:

  • $ ./prova_getopts_silenzioso.sh -f
    Opzione non valida: -f
    OPTIND è 2
    Termino
    $ ./prova_getopts_silenzioso.sh -b
    -b richede un parametro, che non è stato passato
    OPTIND è 2
    Termino

Considerazioni sugli esempi d'uso

  • getopts restituisce un exit status pari a 1 se incontra un parametro che non corrisponde a una opzione prevista. Per gli script in questi esempi, è quindi necessario scrivere per ultimi i parametri che si vogliono analizzare a valle del ciclo while. Se questi sono interpretabili come opzioni, vanno separati da un doppio trattino. In realtà, è possibile una gestione più articolata di questa tipologia di parametri, che però esula dalle finalità di questa guida introduttiva e per la quale si rimanda alla sezione programmazione del forum.

  • 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 continua il parsing dopo aver comunicato l'errore. 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 'b' e 'd'. Questa modalità risulta molto comoda nella fase iniziale di implementazione di uno script.
  • L'istruzione shift successiva al ciclo while ha lo scopo di eliminare dalla stringa dei parametri posizionali quelli che sono già stati analizzati. Il parametro OPTIND assicura infatti di ottenere lo slittamento verso sinistra di tutti i parametri già letti. In questo modo, lo script è in grado di gestire successivamente anche eventuali ulteriori parametri posizionali.

  • È utile ricordare che OPTIND contiene l'indice del parametro posizionale del prossimo argomento da processare e quindi non viene incrementato fino ad aver esaurito l'analisi di tutte le opzioni scritte attaccate.

Ulteriori risorse


CategoryNuoviDocumenti