2010-04-27 16 views
10

Ho appena scoperto che getopt non è multipiattaforma (in particolare per FreeBSD e Linux). Qual è la soluzione migliore per questo problema?getopt cross-platform per uno script di shell

+0

Se hai iniziato utilizzando GNU getopt con lunghe opzioni, ecc, e stanno cercando di rendere il codice esistente portatile con il minor numero di modifiche possibile, quindi è possibile trovare http://stackoverflow.com/a/37087374/324105 utile. – phils

risposta

14

Utilizzare getopts (con una "s").

Secondo Bash FAQ 35:

meno che non sia la versione da util-linux, e si utilizza la sua modalità avanzata, non usare mai getopt (1). getopt non può gestire stringhe di argomenti vuoti o argomenti con spazi bianchi incorporati. Per favore dimentica che è mai esistito.

La shell POSIX (e altri) offrono getopts che è invece sicuro da utilizzare.

+0

Io uso la "S" mnemonica per Shell, getopt "S" è incorporata in BASH –

+0

@Dennis Williamson Si prega di aggiornare la risposta: in base alla voce delle FAQ (aggiornata): ** A meno che non sia la versione di util-linux, e tu usa la sua modalità avanzata, non usare mai getopt (1). ... ** – Florian

+0

@Florian: aggiornato. Grazie. –

0

La sintassi di base per getopt è multipiattaforma.

getopt vi: -v -i 100 file 
27

Esistono essenzialmente due versioni del comando getopt: la versione originale e la versione potenziata GNU. La versione migliorata GNU è retrocompatibile con la versione originale, quindi se si utilizzano solo le funzionalità della versione originale funzionerà con entrambi.

rilevare quale versione di getopt è disponibile

è possibile rilevare che versioni e utilizzare le funzionalità avanzate se la versione GNU, migliorata, è disponibile, e ci si limita alle caratteristiche originali se la versione GNU, migliorata, è non disponibile. La versione avanzata ha un'opzione -T per testare quale versione è disponibile.

getopt -T > /dev/null 
if [ $? -eq 4 ]; then 
    # GNU enhanced getopt is available 
    set -- `getopt --long help,output:,version --options ho:v -- "[email protected]"` 
else 
    # Original getopt is available 
    set -- `getopt ho:v "[email protected]"` 
fi 

Considerare l'utilizzo di comando integrato shell getopts (con una "s"), invece, perché è più portatile. Tuttavia, getopts non supporta le opzioni lunghe (ad esempio --help).

Se si desiderano opzioni lunghe, utilizzare getopt e utilizzare il test precedente per verificare se la versione potenziata GNU di getopt è disponibile o meno. Se la versione avanzata non è disponibile, lo script può degradarsi in modo gradevole utilizzando la versione originale di getopt (senza supporto per nomi di opzioni lunghe e senza supporto per spazi bianchi) o utilizzando getopts (senza supporto per nomi di opzioni lunghi).

Utilizzando GNU, migliorata getopt correttamente

Ottenere la versione avanzata GNU per elaborare gli argomenti con uno spazio adeguato è difficile. Ecco come si fa:

ARGS=`getopt --long help,output:,verbose --options ho:v -- "[email protected]"` 
if [ $? -ne 0 ]; then 
    echo "Usage error (use -h for help)" >&2 
    exit 2 
fi 
eval set -- $ARGS 

# Parameters are now sorted: options appear first, followed by --, then arguments 
# e.g. entering: "foo bar" -o abc baz -v 
#  produces: -o 'abc' -v -- 'foo bar' 'baz' 

Il segreto è quello di utilizzare "[email protected]" dove le virgolette sono molto importanti (in linea 1), e per il evalimpostato comando (in linea 6).

Quindi errori generati da getopt possono essere rilevati e trattati, la chiamata a getopt viene eseguita separatamente dalla eval con i due legati dalla variabile ARGS.

esempio di lavoro completo

PROG=`basename $0` 

getopt -T > /dev/null 
if [ $? -eq 4 ]; then 
    # GNU enhanced getopt is available 
    ARGS=`getopt --name "$PROG" --long help,output:,verbose --options ho:v -- "[email protected]"` 
else 
    # Original getopt is available (no long option names, no whitespace, no sorting) 
    ARGS=`getopt ho:v "[email protected]"` 
fi 
if [ $? -ne 0 ]; then 
    echo "$PROG: usage error (use -h for help)" >&2 
    exit 2 
fi 
eval set -- $ARGS 

while [ $# -gt 0 ]; do 
    case "$1" in 
     -h | --help)  HELP=yes;; 
     -o | --output) OUTFILE="$2"; shift;; 
     -v | --verbose) VERBOSE=yes;; 
     --)    shift; break;; # end of options 
    esac 
    shift 
done 

if [ $# -gt 0 ]; then 
    # Remaining parameters can be processed 
    for ARG in "[email protected]"; do 
    echo "$PROG: argument: $ARG" 
    done 
fi 

echo "$PROG: verbose: $VERBOSE" 
echo "$PROG: output: $OUTFILE" 
echo "$PROG: help: $HELP" 

Questo esempio può essere scaricato dal https://gist.github.com/hoylen/6607180

La tabella di confronto sui Wikipedia's entry on getopts a confronto le diverse caratteristiche.

+0

Sì, 'getopts' (con una s) è un'altra opzione. I puristi della portabilità preferirebbero comunque optare perché i getopts non erano disponibili negli antichi gusci di Bourne prima del 1986, ma questa è una scusa perché la maggior parte/tutte le moderne shell supportano l'opzione. Un motivo migliore è quello di facilitare l'utilizzo del getup GNU migliorato, se disponibile. Il getopt GNU migliorato consente agli operandi di essere combinati con opzioni e supporta nomi di opzioni lunghi (entrambe le funzionalità che getopts non supporta - si veda [tabella di confronto] [1]). – Hoylen

+0

Perché stampa un '-' vuoto quando eseguo 'eval set - $ ARGS'? È molto irritante – Hindol

Problemi correlati