2010-04-27 4 views
10

Ich habe gerade herausgefunden, dass getopt ist nicht plattformübergreifend (insbesondere für FreeBSD und Linux). Was ist die beste Problemumgehung für dieses Problem?Cross-Plattform-getopt für ein Shell-Skript

+0

Wenn Sie begann mit aus GNU getopt mit langen Optionen etc, und schauen, um Ihre vorhandenen Code machen Portable mit so wenig Änderungen wie möglich, dann finden Sie http://stackoverflow.com/a/37087374/324105 nützlich. – phils

Antwort

14

Verwenden Sie getopts (mit einem "s").

Nach Bash FAQ 35:

Es sei denn, es ist die Version von util-linux, und Sie seinen erweiterten Modus nie getopt verwenden (1). getopt kann keine leeren Argumente oder Argumente mit eingebetteten Leerzeichen verarbeiten. Bitte vergiss, dass es jemals existiert hat.

Die POSIX-Shell (und andere) bieten getopts, die stattdessen sicher verwendet werden können.

+0

Ich benutze die Mnemonic "S" für Shell, getopt "S" ist in BASH –

+0

@Dennis Williamson Bitte aktualisieren Sie Ihre Antwort: Nach dem (aktualisierten) FAQ-Eintrag: ** Es sei denn, die Version von util-linux, und Sie Verwenden Sie den erweiterten Modus, verwenden Sie nie getopt (1). ... ** – Florian

+0

@Florian: Aktualisiert. Vielen Dank. –

0

Die grundlegende Syntax für getopt ist plattformübergreifend.

getopt vi: -v -i 100 file 
27

Es gibt im Wesentlichen zwei Versionen des Befehls getopt: die Originalversion und die erweiterte GNU-Version. Die GNU Enhanced Version ist abwärtskompatibel zur Originalversion. Wenn Sie also nur die Funktionen der Originalversion verwenden, wird es mit beiden funktionieren.

ermitteln, welche Version von getopt verfügbar ist

können Sie erkennen, welche Version verfügbar ist und die erweiterten Funktionen verwenden, wenn der GNU erweiterte Version verfügbar ist, und sich auf die ursprünglichen Funktionen zu begrenzen, wenn der GNU erweiterte Version ist Nicht verfügbar. Die erweiterte Version verfügt über eine -T Option zum Testen, welche Version verfügbar ist.

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 

Betrachten Sie mit Hilfe der integrierten in Shell-Befehl getopts (mit einem "s") statt, weil es mehr tragbar ist. getopts unterstützt jedoch keine langen Optionen (z. B. --help).

Wenn Sie lange Optionen mögen, verwenden Sie getopt und verwenden Sie den obigen Test, um zu sehen, ob die GNU Enhanced Version von getopt verfügbar ist oder nicht. Wenn die erweiterte Version nicht verfügbar ist, kann das Skript die ursprüngliche Version von getopt (ohne Unterstützung für lange Optionsnamen und keine Whitespace-Unterstützung) oder getopts (ohne Unterstützung für lange Optionsnamen) ordnungsgemäß herabsetzen.

Mit GNU verbesserte getopt richtig

die GNU erweiterte Version Erste Argumente mit Leerzeichen zu verarbeiten richtig ist schwierig. Hier ist, wie es gemacht wird:

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' 

Das Geheimnis ist "[email protected]" zu verwenden, wo die doppelten Anführungszeichen sehr wichtig sind (in Zeile 1), und auf eval die gesetzt Befehl (in Zeile 6).

So können Fehler von getopt erkannt und behandelt werden, der Aufruf an getopt erfolgt getrennt von der eval mit den beiden durch die ARGS-Variable verknüpft.

Komplettes Arbeits Beispiel

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" 

Dieses Beispiel kann aus https://gist.github.com/hoylen/6607180

Die Vergleichstabelle auf Wikipedia's entry on getopts vergleicht die verschiedenen Funktionen heruntergeladen werden.

+0

Ja, 'getopts' (mit einem s) ist eine andere Option. Portabilität puristen würden immer noch getopt bevorzugen, da getopts in alten Bourne-Shells vor 1986 nicht verfügbar war, aber das ist ein schlechter Grund, da die meisten/modernen Shells Optionen bekommen. Ein besserer Grund ist es, GNU enhanced getup einfach zu nutzen, wenn es verfügbar ist. Das GNU Enhanced getopt erlaubt Operanden, mit Optionen gemischt zu werden und unterstützt lange Optionsnamen (beide Funktionen, die getopts nicht unterstützt - siehe [Vergleichstabelle] [1]). – Hoylen

+0

Warum gibt es ein leeres '-', wenn ich 'eval set - $ ARGS' starte? Es ist sehr irritierend. – Hindol

Verwandte Themen