Come posso rilevare che nessuna opzione è stata passata con getopts?


19

Ho questo codice -

#getoptDemo.sh
usage()
{
    echo "usage: <command> options:<w|l|h>"
}
while getopts wlh: option
do
    case $option in
            (w)
                    name='1';;
            (l)
                    name='2';;
            (h)
                    name='3';;
            (*)
                    usage
                    exit;;
    esac
done
print 'hi'$name

Quando corro bash getoptDemos.sh(senza l'opzione) stampa hiinvece di chiamare la funzione usage. Chiama l'utilizzo quando vengono fornite opzioni diverse da w, heel. Quindi non può funzionare quando non vengono specificate opzioni.

Ho provato ad utilizzare ?, \?, :al posto di *, ma non riesco a ottenere quello che volevo. Voglio dire, tutto il docssu getoptdice che da usare ?.

Che cosa sto facendo di sbagliato?


In quale shell lo stai eseguendo?
Giuliano

Lo sto eseguendo sotto/bin/bash
Hussain Tamboli l'

Risposte:


15

Quando esegui questo script senza alcuna opzione, getopt restituirà false, quindi non entrerà affatto nel ciclo. Scenderà sulla stampa: è questo ksh / zsh?

Se devi avere un'opzione, la soluzione migliore è testare $ name dopo il loop.

if [ -z "$name" ]
then
   usage
   exit
fi

Ma assicurati che $namefosse vuoto prima di chiamare getopts(in quanto potrebbe esserci stato un $nameambiente ricevuto dalla shell all'avvio)

unset name

(prima del getoptsciclo)


no. è bash. Quindi, come posso ottenere quello che voglio: gestire la no argumentcondizione usando bash.
Hussain Tamboli,

Se vuoi un'opzione obbligatoria, non penso che sia possibile - è probabilmente il motivo per cui vengono chiamate opzioni :) Puoi testare $ name, dopo il ciclo, per assicurarti che sia stato impostato. if [-z "$ name"]; quindi utilizzo; Uscita ; fi
Julian,

Grazie. il codice sopra ha davvero aiutato. È un peccato getoptsche non abbia una tale disposizione. Ciò che è peggio di così non può non votarti.
Hussain Tamboli,

e se avessi eseguito un'altra shell? zsh, sh. qualche shell diverso da bash si prende cura di questa condizione?
Hussain Tamboli,

20

getoptselabora le opzioni a turno. Questo è il suo lavoro. Se l'utente non passa alcuna opzione, la prima chiamata di getoptsesce dal ciclo while.

Se nessuna delle opzioni accetta un argomento, il valore di OPTINDindica quante opzioni sono state passate. In generale, OPTINDè il numero di argomenti che sono opzioni o argomenti di opzioni, al contrario di argomenti non-opzione (operandi).

while getopts …; do …; done
if [ $OPTIND -eq 1 ]; then echo "No options were passed"; fi
shift $((OPTIND-1))
echo "$# non-option arguments"

In ogni caso, non stai cercando di determinare se non ci fossero opzioni, ma se nessuna delle nameopzioni di impostazione è stata passata. Quindi controlla se namenon è impostato (e assicurati di disinserirlo prima) .


1
Grazie. +1 per te. quando inserisco le ultime 3 righe del tuo codice in sample.sh ed eseguo bash sample.sh -abc file.txtdà - 1 non-option arguments. come faccio a sapere quante opzioni sono state fornite. (qui 3)
Hussain Tamboli,

1
Strano nessuno ha commentato questo leggero bug - se non viene fornita alcuna opzione, OPTIND sarà 1 dopo quel ciclo 'while getopts ...'. Pertanto, il controllo if dovrebbe verificare l'uguaglianza con 1, non con zero.
Daniel,

4

Se lo script deve ricevere gli argomenti delle opzioni in ogni caso, posizionare questo blocco all'inizio (prima di getops).

if [[ ! $@ =~ ^\-.+ ]]
then
  #display_help;
fi

Il blocco verifica che la stringa del parametro non inizi con il -simbolo, ciò indica che il primo parametro non è un argomento opzione.


2

Lo controllerei con una variabile. Se getopts non passa mai il ciclo in caso di nessun argomento, puoi usarlo ad esempio in questo modo:

#getoptDemo.sh
usage()
{
    echo "usage: <command> options:<w|l|h>"
}

no_args="true"
while getopts wlh: option
do
    case $option in
            (w)
                    name='1';;
            (l)
                    name='2';;
            (h)
                    name='3';;
            (*)
                    usage
                    exit;;
    esac
    no_args="false"
done

[[ "$no_args" == "true" ]] && { usage; exit 1; }

print 'hi'$name

0

Poco prima del tuo getoptsblocco, controlla se$1 (il primo argomento / opzione che hai passato sulla riga di comando) è uguale a una stringa vuota. In tal caso, stampa il messaggio di utilizzo ed esci (o esegui alcune funzioni "nessuna opzione" se sei un anarchico), altrimenti getoptsanalizza le opzioni come di consueto.

Il motivo per cui questa funzionalità non è inclusa in getopts è perché puoi già realizzarla in bash con un "if-else". Esempio:

if [[ $1 == "" ]]; then
    Your_Usage_Function;
    exit;
else
   #parse options with getopts code block here;
fi

Ha senso?

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.