2011-10-05 14 views
9

Sto usando getopt (non getops) per fornire la possibilità per il mio script bash di elaborare opzioni e opzioni (sia long che opzione e moduli short -o).Trapping getopt opzioni non valide

Mi piacerebbe essere in grado di intercettare le opzioni non valide e gestirle, in genere echeggiando che l'utente dovrebbe provare cmd --help e quindi uscire dallo script.

fatto è che le opzioni non valide vengono catturati da getopt, a sua volta in uscita un messaggio del tipo "getopt: opzione non valida - 'x'"

Ecco il modello che sto usando per impostare il mio getopt parametri:

set -- $(getopt -o $SHORT_OPTIONS -l $LONG_OPTIONS -- "[email protected]") 

dove entrambi $ long_options e $ SHORT_OPTIONS sono un elenco delimitato da virgole di opzioni.

Ecco come ho gestire l'elaborazione delle opzioni:

while [ $# -gt 0 ] 
    do 
     case "$1" in 
      -h|--help) 
       cat <<END_HELP_OUTPUT 

    Help 
    ---- 

    Usage: ./cmd.sh 

    END_HELP_OUTPUT 

       shift; 
       exit 
       ;; 
      --opt1) 
       FLAG1=true 
       shift 
       ;; 
      --opt2) 
       FLAG2=true 
       shift 
       ;; 
      --) 
       shift 
       break 
       ;; 
      *) 
       echo "Option $1 is not a valid option." 
       echo "Try './cmd.sh --help for more information." 
       shift 
       exit 
       ;; 
     esac 
    done 

getopt -q sarà sopprimere l'uscita, ma il mio sistema di intrappolamento all'interno dell'istruzione case non riesce ancora a fare quello che mi aspetto. Invece, il programma viene eseguito, nonostante gli argomenti non validi.

risposta

8

This sorta di stile funziona per me:

params="$(getopt -o d:h -l diff:,help --name "$cmdname" -- "[email protected]")" 

if [ $? -ne 0 ] 
then 
    usage 
fi 

eval set -- "$params" 
unset params 

while true 
do 
    case $1 in 
     -d|--diff) 
      diff_exec=(${2-}) 
      shift 2 
      ;; 
     -h|--help) 
      usage 
      exit 
      ;; 
     --) 
      shift 
      break 
      ;; 
     *) 
      usage 
      ;; 
    esac 
done 
+0

In tal caso *) viene raggiunto? – jarno

+0

@jarno Se si verifica una mancata corrispondenza tra l'istruzione 'case' e ​​la chiamata' getopt', verrà catturata lì. È solo una programmazione difensiva. – l0b0

0

Non sono sicuro se questo può aiutare, ma getopt (1) utilizza getopt (3) e se non ricordo male getopt (3) segnalazione errore sopprimere se il carattere del pugno optstring è un due punti.

+0

Uso ':' come primo carattere all'interno optstring sopprime la messaggio in uscita. Tuttavia, il codice di ritorno da getopt (1) è ancora diverso da zero e l'opzione non riconosciuta non viene emessa da getopt (1). –

1

Questa non è la soluzione più robusta, ma è ragionevole; si basa su quanto segue:

  • Il messaggio di errore che getopt stampe è preceduto da "getopt:"
  • L'ipotesi è che è accettabile per passare attraverso una versione ripulita del messaggio di errore getopt s', aumentata con informazioni personalizzate.

Codice frammento:

# Invoke getopt; suppress its stderr initially. 
args=$(getopt -o $SHORT_OPTIONS -l $LONG_OPTIONS -- "[email protected]" 2>/dev/null) 
if [[ $? -ne 0 ]]; then # getopt reported failure 
    # Rerun the same getopt command so we can capture stderr output *only* this time. 
    # Inefficient (and a potential maintenance headache, if literals were involved), but this will only execute in case of invalid input. 
    # Alternatively, redirect the first getopt invocation's stderr output to a temp. file and read it here. 
    errmsg=$(getopt -o $SHORT_OPTIONS -l $LONG_OPTIONS -- "[email protected]" 2>&1 1>&-) 
    # Strip getopt's prefix and augment with custom information. 
    echo -e "${errmsg#getopt: }\nTry './cmd.sh --help for more information." 1>&2 
    exit 1 
fi 
+0

Potrebbe funzionare, eh? Come hai detto tu, piuttosto fragile. –

+0

@TomAuger: Se pensi che "abbastanza fragile" parafrasa adeguatamente "non il più robusto, ma è ragionevole", devi eseguire una shell in lingua inglese incompatibile. Invariabilmente, tentare di ottenere informazioni da 'getopt' in modo affidabile che non è stato progettato per segnalare a livello di codice sarà complicato. Detto questo, la parte in cui si assume che l'output di stderr viene prima è davvero traballante, quindi ho rivisto il codice per affrontarlo. Se riesci a catturare lo stdout e lo stderr in variabili separate da un'unica esecuzione di comando (non implicando la creazione esplicita di file temporanei), fammi sapere. – mklement0

1

Avete utilizzare getopt a tutti? Se si utilizza solo

while [ $# -gt 0 ]; do 
    case "$1" in 
    -d|--diff) 
     diff_exec=(${2-}) 
     shift 
     ;; 
    -h|--help) 
     usage 
     exit 
     ;; 
    --) 
     break 
     ;; 
    *) 
     usage 
     ;; 
    esac 
    shift 
done 

Quindi il proprio codice sta eseguendo il controllo.

1

ho trovato questo lavoro come l'ultimo elemento nella dichiarazione getopts caso:

*) eval echo "non riconosciuta arg \ $$ [OPTIND-1]"; utilizzo; Uscita ;;

0

Ecco una parsing della riga di comando che ho usato. Potrebbe essere migliorato con più logica di analisi per gestire opzioni e parametri mancanti.

Per la linea di comando: -a -b AA BB CC -c, il risultato s/ba = AA b = c = BB CC

OPT=("[email protected]") # Parses the command line into words. 

for [[ I=0;I<${#OPT[@]};I++ ]] 
    do 
     case "${OPT[$I]}" in   
     -a) a=${OPT[$I+1]} ;;   
     -b) b=${OPT[$I+1]} ;;   
     -c) c=${OPT[$I+1]} ;;  
     esac 
    done 
Problemi correlati