Come utilizzare getopts per analizzare le opzioni dello script della shell di Linux
Pubblicato: 2022-06-25 Vorresti che gli script della tua shell Linux gestissero le opzioni e gli argomenti della riga di comando in modo più elegante? L'incorporato Bash getopts
ti consente di analizzare le opzioni della riga di comando con precisione ed è anche facile. Ti mostriamo come.
Presentazione del getopts integrato
Il passaggio di 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 la seconda e così via.
Ma se vuoi passare le opzioni a uno script, la situazione diventa rapidamente più complessa. Quando diciamo opzioni intendiamo le opzioni, i flag o gli interruttori che programmi come ls
possono gestire. Sono preceduti da un trattino “ -
” e di solito fungono da indicatore del programma per attivare o disattivare alcuni aspetti della sua funzionalità.
Il comando ls
ha oltre 50 opzioni, principalmente relative alla formattazione del suo output. L'opzione -X
(ordina per estensione) ordina l'output in ordine alfabetico in base all'estensione del file. L'opzione -U
(non ordinata) elenca in base all'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 option argument , ad esempio, l' ls -w
(width) 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
. Questo è un piccolo programma di utilità, non un built-in. Esistono molte versioni differenti di getopt
con comportamenti differenti, mentre getops
segue le linee guida POSIX.
digita getopts
digita getopt
Poiché getopt
non è un builtin, non condivide alcuni dei vantaggi automatici offerti da getopts
, come la gestione ragionevole degli spazi bianchi. Con getopts
, la shell Bash esegue lo script e la shell Bash esegue l'analisi delle opzioni. Non è necessario invocare un programma esterno per gestire l'analisi.
Il compromesso è che getopts
non gestisce nomi di opzioni di formato lungo con doppio trattino. Quindi puoi usare opzioni formattate come -w
ma non " ---wide-format
". D'altra parte, se hai uno script che accetta le opzioni -a
, -b
e
, -c
getopts
ti consente di combinarle come -abc
, -bca
o -bac
e così via.
Stiamo discutendo e dimostrando getopts
in questo articolo, quindi assicurati di aggiungere la "s" finale al nome del comando.
CORRELATI: Come sfuggire agli spazi nei percorsi dei file sulla riga di comando di Windows
Un breve riepilogo: gestione dei valori dei parametri
Questo script non usa 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 # ottieni le variabili una per una echo "Variabile uno: $1" echo "Variabile due: $2" echo "Variabile tre: $ 3" # scorre le variabili per var in " $@" do eco "$ var" fatto
I parametri sono accessibili all'interno dello script come variabili $1
, $2
o $3
.
Copia questo testo in un editor e salvalo come file chiamato "variables.sh". Dovremo renderlo eseguibile con il comando chmod
. Dovrai eseguire questo passaggio per tutti gli script di cui discutiamo. Basta sostituire ogni volta il nome del file di script appropriato.
chmod +x variabili.sh
Se eseguiamo il nostro script senza parametri, otteniamo questo output.
./variabili.sh
Non abbiamo passato alcun parametro, quindi lo script non ha valori da segnalare. Forniamo alcuni parametri questa volta.
./variables.sh come geek
Come previsto, le variabili $1
, $2
e $3
sono state impostate 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 come geek sito web
Se mettiamo le virgolette intorno a due delle parole, vengono trattate come un parametro.
./variables.sh come "smanettare"
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 mettendo tutte le opzioni, con o senza argomenti, prima dei 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
Usiamo getopts
in un ciclo while
. Ogni iterazione del ciclo funziona su un'opzione passata allo script. In ogni caso, la variabile OPTION
è impostata sull'opzione identificata da getopts
.
Ad ogni iterazione del ciclo, getopts
passa all'opzione successiva. Quando non ci sono più opzioni, getopts
restituisce false
e il ciclo while
termina.
La variabile OPTION
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 mentre getopts 'abc' OPZIONE; fare caso "$OPTION" in un) echo "Opzione a usata" ;; b) echo "Opzione b utilizzata" ;; c) echo "Opzione c utilizzata" ;; ?) echo "Utilizzo: $(nome base $0) [-a] [-b] [-c]" uscita 1 ;; esac fatto
Questa è la linea che definisce il ciclo while.
mentre getopts 'abc' OPZIONE; fare
Il comando getopts
è seguito dalla stringa delle 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 dalla 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 "Utilizzo: $(nome base $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 è contenuto in $0
negli script Bash.
Usiamo questo script con diverse combinazioni di riga di comando.
./opzioni.sh -a
./opzioni.sh -a -b -c
./opzioni.sh -ab -c
./opzioni.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?
./opzioni.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. Tutto quello che dobbiamo fare è inserire i due punti ” :
” come primo carattere della stringa delle 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' OPZIONE; fare caso "$OPTION" in un) echo "Opzione a usata" ;; b) echo "Opzione b utilizzata" ;; c) echo "Opzione c utilizzata" ;; ?) echo "Utilizzo: $(nome base $0) [-a] [-b] [-c]" uscita 1 ;; esac fatto
Quando lo eseguiamo e generiamo un errore, riceviamo i nostri messaggi di errore senza alcun messaggio di shell.
./opzioni2.sh.sh -d
Utilizzo di getopts con argomenti di opzione
Per dire a getopts
che un'opzione sarà seguita da un argomento, metti i due punti ” :
” subito dietro la lettera dell'opzione nella stringa delle opzioni.
Se seguiamo "b" e "c" nella nostra stringa di opzioni con due punti, getopt
si aspetterà argomenti per queste opzioni. Copia questo script nel tuo editor e salvalo come "arguments.sh" e rendilo eseguibile.
Ricorda, i primi 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 nella variabile OPTARG
. Se vuoi usare questo valore altrove nel tuo script, dovrai copiarlo in un'altra variabile.
#!/bin/bash while getopts ':ab:c:' OPZIONE; fare caso "$OPTION" in un) echo "Opzione a usata" ;; b) argB="$OPTARG" echo "Opzione b usata con: $argB" ;; c) argC="$OPTARG" echo "Opzione c usata con: $argC" ;; ?) echo "Utilizzo: $(nome base $0) [-a] [-b argomento] [-c argomento]" uscita 1 ;; esac fatto
Eseguiamolo e vediamo come funziona.
./arguments.sh -a -b "come 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 ciclo while
è terminato e tutte le opzioni sono state gestite, proveremo ad accedere ai parametri regolari. Stamperemo il valore in $1
.
Salva questo script come "arguments2.sh" e rendilo eseguibile.
#!/bin/bash while getopts ':ab:c:' OPZIONE; fare caso "$OPTION" in un) echo "Opzione a usata" ;; b) argB="$OPTARG" echo "Opzione b usata con: $argB" ;; c) argC="$OPTARG" echo "Opzione c usata con: $argC" ;; ?) echo "Utilizzo: $(nome base $0) [-a] [-b argomento] [-c argomento]" uscita 1 ;; esac fatto echo "La variabile uno è: $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 viene utilizzata una qualsiasi opzione, le variabili $1
in poi vengono riempite con i flag di opzione e i loro argomenti. Nell'ultimo esempio, $4
conterrebbe il valore del parametro "dave", ma come puoi accedervi nel tuo script se non sai quante opzioni e argomenti verranno utilizzati?
La risposta è usare OPTIND
e il comando shift
.
Il comando shift
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 il 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 in più rispetto al numero di opzioni. Quindi, se utilizziamo i parametri shift to trim (OPTIND-1)
dall'elenco dei parametri, rimarremo con i parametri normali da $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:' OPZIONE; fare caso "$OPTION" in un) echo "Opzione a usata" ;; b) argB="$OPTARG" echo "Opzione b usata con: $argB" ;; c) argC="$OPTARG" echo "Opzione c usata con: $argC" ;; ?) echo "Utilizzo: $(nome base $0) [-a] [-b argomento] [-c argomento]" uscita 1 ;; esac fatto echo "Prima - una variabile è: $1" shift "$(($OPTIND -1))" echo "Dopo - la variabile uno è: $1" echo "Il resto degli argomenti (operandi)" per x in "$@" fare eco $x fatto
Lo eseguiremo con un mix di opzioni, argomenti e parametri.
./arguments3.sh -a -c how-to-geek "dave dee" dozy beaky mick tich
Possiamo vedere che prima di chiamare shift
, $1
conteneva "-a", ma dopo il comando shift $1
mantiene 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. Con getopts
puoi creare script che gestiscono opzioni, argomenti e parametri della riga di comando esattamente come dovrebbero fare gli script nativi conformi a POSIX.