
Vorresti che gli script della tua shell Linux gestissero le opzioni e gli argomenti della riga di comando in modo più elegante? Il Bash getopts builtin ti consente di analizzare le opzioni della riga di comando con precisione ed è anche facile. Ti mostriamo come.
Presentazione del getopts integrato
Passando i valori in uno script Bash è piuttosto semplice. Chiama il tuo script dalla riga di comando o da un altro script e fornisci il tuo elenco di valori dietro il nome dello script. È possibile accedere a questi valori all’interno dello script come variabili, a partire da $1 per la prima variabile, $2 per il secondo e così via.
Ma se vuoi passare opzioni a un copione, la situazione diventa rapidamente più complessa. Quando diciamo opzioni intendiamo le opzioni, i flag o gli interruttori che piacciono ai programmi ls può gestire. Sono preceduti da un trattino”-” e di solito fungono da indicatore del programma per attivare o disattivare alcuni aspetti della sua funzionalità.
Il ls comando ha oltre 50 opzioni, principalmente relative alla formattazione del suo output. Il -X (ordina per estensione) l’opzione ordina l’output in ordine alfabetico in base all’estensione del file. Il -U elenchi di opzioni (non ordinate) per ordine di directory.
Le opzioni sono proprio questo: sono opzionali. Non sai quali opzioni, se presenti, l’utente sceglierà di utilizzare e nemmeno in quale ordine potrebbero elencarle sulla riga di comando. Ciò aumenta la complessità del codice richiesto per analizzare le opzioni.
Le cose diventano ancora più complicate se alcune delle tue opzioni accettano un argomento, noto come an argomento dell’opzioneAd esempio, il ls -w L’opzione (larghezza) prevede di essere seguita da un numero, che rappresenta la larghezza massima di visualizzazione dell’output. E, naturalmente, potresti passare altri parametri nel tuo script che sono semplicemente valori di dati, che non sono affatto opzioni.
Per fortuna getopts gestisce questa complessità per te. E poiché è un built-in, è disponibile su tutti i sistemi che hanno la shell Bash, quindi non c’è nulla da installare.
Nota: getopts Non getopt
C’è una vecchia utility chiamata getopt . Questa è una piccola utilità programma, non un built-in. Esistono molte versioni differenti di getopt con comportamenti differenti, mentre il getops builtin segue le linee guida POSIX.
type getopts
type getopt

Perché getopt non è un built-in non condivide alcuni dei vantaggi automatici che getopts fa, come gestire gli spazi bianchi in modo sensato. Insieme a getopts, la shell Bash sta eseguendo il tuo script e la shell Bash sta eseguendo l’analisi delle opzioni. Non è necessario invocare un programma esterno per gestire l’analisi.
Il compromesso è getopts non gestisce i nomi delle opzioni di formato lungo con doppio trattino. Quindi puoi usare opzioni formattate come -w ma no ” ---wide-format.” D’altra parte, se hai uno script che accetta le opzioni -a , -b e , -cgetopts ti consente di combinarli come -abc, -bcao -bac e così via.
Stiamo discutendo e dimostrando getopts in questo articolo, quindi assicurati di aggiungere la “s” finale al nome del comando.
IMPARENTATO: Come eseguire l’escape degli spazi nei percorsi dei file sulla riga di comando di Windows
Un breve riepilogo: gestione dei valori dei parametri
Questo script non utilizza opzioni tratteggiate come -a o -b . Accetta parametri “normali” sulla riga di comando e a questi si accede all’interno dello script come valori.
#!/bin/bash # get the variables one by one echo "Variable One: $1" echo "Variable Two: $2" echo "Variable Three: $3" # loop through the variables for var in "$@" do echo "$var" done
I parametri sono accessibili all’interno dello script come variabili $1, $2o $3 .
Copia questo testo in un editor e salvalo come file chiamato “variables.sh”. Dovremo renderlo eseguibile con chmod comando. Dovrai eseguire questo passaggio per tutti gli script di cui discutiamo. Basta sostituire ogni volta il nome del file di script appropriato.
chmod +x variables.sh

Se eseguiamo il nostro script senza parametri, otteniamo questo output.
./variables.sh

Non abbiamo passato alcun parametro, quindi lo script non ha valori da segnalare. Forniamo alcuni parametri questa volta.
./variables.sh how to geek

Come previsto, le variabili $1, $2 e $3 sono stati impostati sui valori dei parametri e li vediamo stampati.
Questo tipo di gestione dei parametri uno a uno significa che dobbiamo sapere in anticipo quanti parametri ci saranno. Il ciclo nella parte inferiore dello script non si preoccupa di quanti parametri ci sono, li scorre sempre tutti.
Se forniamo un quarto parametro, non viene assegnato a una variabile, ma il ciclo lo gestisce comunque.
./variables.sh how to geek website

Se mettiamo le virgolette intorno a due delle parole, vengono trattate come un parametro.
./variables.sh how "to geek"

Se avremo bisogno del nostro script per gestire tutte le combinazioni di opzioni, opzioni con argomenti e parametri di tipo di dati “normali”, avremo bisogno di separare le opzioni dai parametri normali. Possiamo ottenerlo inserendo tutte le opzioni, con o senza argomenti,prima i parametri regolari.
Ma non corriamo prima di poter camminare. Diamo un’occhiata al caso più semplice per la gestione delle opzioni della riga di comando.
Opzioni di gestione
Noi usiamo getopts in un while ciclo continuo. Ogni iterazione del ciclo funziona su un’opzione passata allo script. In ogni caso, la variabile OPTION è impostato sull’opzione identificata da getopts.
Ad ogni iterazione del ciclo, getopts passa all’opzione successiva. Quando non ci sono più opzioni, getopts ritorna false e il while il ciclo esce.
Il OPTION variabile viene confrontata con i modelli in ciascuna delle clausole di istruzione case. Poiché stiamo usando un’istruzione case, non importa in quale ordine sono fornite le opzioni sulla riga di comando. Ciascuna opzione viene rilasciata nella dichiarazione del caso e viene attivata la clausola appropriata.
Le singole clausole nell’istruzione case facilitano l’esecuzione di azioni specifiche dell’opzione all’interno dello script. In genere, in uno script del mondo reale, imposti una variabile in ciascuna clausola e queste agiranno come flag più avanti nello script, consentendo o negando alcune funzionalità.
Copia questo testo in un editor e salvalo come uno script chiamato “options.sh” e rendilo eseguibile.
#!/bin/bash
while getopts 'abc' OPTION; do
case "$OPTION" in
a)
echo "Option a used" ;;
b)
echo "Option b used"
;;
c)
echo "Option c used"
;;
?)
echo "Usage: $(basename $0) [-a] [-b] [-c]"
exit 1
;;
esac
done
Questa è la linea che definisce il ciclo while.
while getopts 'abc' OPTION; do
Il getopts il comando è seguito da stringa di opzioni. Questo elenca le lettere che useremo come opzioni. Solo le lettere in questo elenco possono essere utilizzate come opzioni. Quindi in questo caso, -d non sarebbe valido. Questo sarebbe intrappolato dal ?) clausola perché getopts restituisce un punto interrogativo “?” per un’opzione non identificata. Se ciò accade, l’utilizzo corretto viene stampato nella finestra del terminale:
echo "Usage: $(basename $0) [-a] [-b] [-c]"
Per convenzione, racchiudere un’opzione tra parentesi “[]” in questo tipo di messaggio di utilizzo corretto significa che l’opzione è facoltativa. Il comando basename rimuove tutti i percorsi di directory dal nome del file. Il nome del file di script viene mantenuto $0 negli script Bash.
Usiamo questo script con diverse combinazioni di riga di comando.
./options.sh -a
./options.sh -a -b -c
./options.sh -ab -c
./options.sh -cab

Come possiamo vedere, tutte le nostre combinazioni di test di opzioni vengono analizzate e gestite correttamente. E se provassimo un’opzione che non esiste?
./options.sh -d

Viene attivata la clausola di utilizzo, il che è positivo, ma riceviamo anche un messaggio di errore dalla shell. Questo potrebbe o non potrebbe avere importanza per il tuo caso d’uso. Se stai chiamando lo script da un altro script che deve analizzare i messaggi di errore, sarà più difficile se anche la shell sta generando messaggi di errore.
Disattivare i messaggi di errore della shell è molto semplice. Non ci resta che mettere i due punti” : ” come primo carattere della stringa di opzioni.
Modifica il tuo file “options.sh” e aggiungi due punti come primo carattere della stringa delle opzioni, oppure salva questo script come “options2.sh” e rendilo eseguibile.
#!/bin/bash
while getopts ':abc' OPTION; do
case "$OPTION" in
a)
echo "Option a used"
;;
b)
echo "Option b used"
;;
c)
echo "Option c used"
;;
?)
echo "Usage: $(basename $0) [-a] [-b] [-c]"
exit 1
;;
esac
done
Quando lo eseguiamo e generiamo un errore, riceviamo i nostri messaggi di errore senza alcun messaggio di shell.
./options2.sh.sh -d

Utilizzo di getopts con argomenti di opzione
Dire getopts che un’opzione sarà seguita da un argomento, metti i due punti ” : ” immediatamente dietro la lettera dell’opzione nella stringa delle opzioni.
Se seguiamo la “b” e la “c” nella nostra stringa di opzioni con i due punti, getopt si aspetteranno argomenti per queste opzioni. Copia questo script nel tuo editor e salvalo come “arguments.sh” e rendilo eseguibile.
Ricorda il primo i due punti nella stringa delle opzioni vengono utilizzati per sopprimere i messaggi di errore della shell: non ha nulla a che fare con l’elaborazione degli argomenti.
quando getopt elabora un’opzione con un argomento, l’argomento viene inserito in OPTARG variabile. Se vuoi usare questo valore altrove nel tuo script, dovrai copiarlo in un’altra variabile.
#!/bin/bash while getopts ':ab:c:' OPTION; do case "$OPTION" in a) echo "Option a used" ;; b) argB="$OPTARG" echo "Option b used with: $argB" ;; c) argC="$OPTARG" echo "Option c used with: $argC" ;; ?) echo "Usage: $(basename $0) [-a] [-b argument] [-c argument]" exit 1 ;; esac done
Eseguiamolo e vediamo come funziona.
./arguments.sh -a -b "how to geek" -c reviewgeek
./arguments.sh -c reviewgeek -a

Quindi ora possiamo gestire le opzioni con o senza argomenti, indipendentemente dall’ordine in cui vengono fornite sulla riga di comando.
Ma per quanto riguarda i parametri regolari? Abbiamo detto in precedenza che sapevamo che avremmo dovuto metterli sulla riga di comando dopo qualsiasi opzione. Vediamo cosa succede se lo facciamo.
Opzioni e parametri di missaggio
Cambieremo il nostro script precedente per includere un’altra riga. Quando il while loop è terminato e tutte le opzioni sono state gestite cercheremo di accedere ai parametri regolari. Stamperemo il valore in $1 .
Salva questo script come “arguments2.sh” e rendilo eseguibile.
#!/bin/bash while getopts ':ab:c:' OPTION; do case "$OPTION" in a) echo "Option a used" ;; b) argB="$OPTARG" echo "Option b used with: $argB" ;; c) argC="$OPTARG" echo "Option c used with: $argC" ;; ?) echo "Usage: $(basename $0) [-a] [-b argument] [-c argument]" exit 1 ;; esac done echo "Variable one is: $1"
Ora proveremo alcune combinazioni di opzioni e parametri.
./arguments2.sh dave
./arguments2.sh -a dave
./arguments2.sh -a -c how-to-geek dave

Quindi ora possiamo vedere il problema. Non appena vengono utilizzate le opzioni, le variabili $1 in poi vengono riempiti con i flag di opzione e i loro argomenti. Nell’ultimo esempio, $4 conterrebbe il valore del parametro “dave”, ma come accedi a quello nel tuo script se non sai quante opzioni e argomenti verranno utilizzati?
La risposta è usare OPTIND e il shift comando.
Il shift Il comando elimina il primo parametro, indipendentemente dal tipo, dall’elenco dei parametri. Gli altri parametri “mischiano”, quindi il parametro 2 diventa il parametro 1, il parametro 3 diventa il parametro 2 e così via. E così $2 diventa $1 , $3 diventa $2 e così via.
Se fornisci shift con un numero, verranno rimossi tanti parametri dall’elenco.
OPTIND conta le opzioni e gli argomenti man mano che vengono trovati ed elaborati. Una volta che tutte le opzioni e gli argomenti sono stati elaborati OPTIND sarà uno superiore al numero di opzioni. Quindi, se usiamo shift per tagliare (OPTIND-1) parametri fuori dall’elenco dei parametri, rimarremo con i parametri normali in $1 in poi.
Questo è esattamente ciò che fa questo script. Salva questo script come “arguments3.sh” e rendilo eseguibile.
#!/bin/bash
while getopts ':ab:c:' OPTION; do
case "$OPTION" in
a)
echo "Option a used"
;;
b)
argB="$OPTARG"
echo "Option b used with: $argB"
;;
c)
argC="$OPTARG"
echo "Option c used with: $argC"
;;
?)
echo "Usage: $(basename $0) [-a] [-b argument] [-c argument]"
exit 1
;;
esac
done
echo "Before - variable one is: $1"
shift "$(($OPTIND -1))"
echo "After - variable one is: $1"
echo "The rest of the arguments (operands)"
for x in "$@"
do
echo $x
done
Lo eseguiremo con un mix di opzioni, argomenti e parametri.
./arguments3.sh -a -c how-to-geek "dave dee" dozy beaky mick tich

Possiamo vederlo prima di chiamare shift , $1 tenuto “-a”, ma dopo il comando shift $1 contiene il nostro primo parametro non opzione, non argomento. Possiamo scorrere tutti i parametri con la stessa facilità con cui possiamo in uno script senza alcuna opzione di analisi.
È sempre bello avere opzioni
La gestione delle opzioni e dei loro argomenti negli script non deve essere complicata. Insieme a getopts puoi creare script che gestiscono opzioni, argomenti e parametri della riga di comando esattamente come dovrebbero fare gli script nativi conformi a POSIX.
