Come utilizzare getopts per analizzare le opzioni dello script della shell di Linux

Pubblicato: 2022-06-25
Lo schermo di un laptop che mostra il testo del terminale.
fatmawati achmad zaenuri/Shutterstock.com

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à.

Come utilizzare il comando ls per elencare file e directory su Linux
CORRELATI Come utilizzare il comando ls per elencare file e directory su Linux

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 

usando il comando type per vedere la differenza tra getop e getops

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 

usando il comando chmod per rendere eseguibile uno script

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

 ./variabili.sh 

eseguire uno script senza parametri

Non abbiamo passato alcun parametro, quindi lo script non ha valori da segnalare. Forniamo alcuni parametri questa volta.

 ./variables.sh come geek 

eseguire uno script con tre parole come parametri

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 

passando quattro parametri a uno script che può gestirne solo tre

Se mettiamo le virgolette intorno a due delle parole, vengono trattate come un parametro.

 ./variables.sh come "smanettare" 

citando due parametri della riga di comando per averli trattati come un unico parametro

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.

Come utilizzare le istruzioni Case negli script Bash
CORRELATI Come utilizzare le istruzioni Case negli script Bash

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 

testare uno script in grado di accettare opzioni della riga di comando di tipo switch

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 

Un'opzione non riconosciuta segnalata dalla shell e dallo script

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 

Un'opzione non riconosciuta segnalata dal solo script

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 

testare uno script in grado di gestire argomenti di opzione

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 

Impossibile accedere ai parametri standard in uno script che accetta argomenti di opzione

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 

Accesso corretto ai parametri standard in uno script che accetta argomenti di opzione

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.