Ich versuche, ein Shell-Skript aufzubauen, das verschiedene Optionen akzeptiert und getopts
eine gute Lösung zu sein scheint, da es die variable Reihenfolge der Optionen und Argumente handhaben kann (glaube ich!).
Ich verwende nur kurze Optionen und für jede kurze Option ist ein entsprechender Wert erforderlich, z. B.: ./command.sh -a arga -g argg -b argb
Ich möchte jedoch zulassen, dass die Optionen in einer unspezifischen Reihenfolge eingegeben werden, wie es die meisten Leute gewohnt sind, mit Shell-Befehlen zu arbeiten .
Der andere Punkt ist, dass ich meine eigenen Überprüfungen der Optionsargumentwerte durchführen möchte, idealerweise innerhalb der case
Anweisungen. Der Grund dafür ist, dass meine Tests :)
in meiner case
Erklärung zu inkonsistenten Ergebnissen geführt haben (wahrscheinlich durch mangelndes Verständnis meinerseits).
Zum Beispiel:
#!/bin/bash
OPTIND=1 # Reset if getopts used previously
if (($# == 0)); then
echo "Usage"
exit 2
fi
while getopts ":h:u:p:d:" opt; do
case "$opt" in
h)
MYSQL_HOST=$OPTARG
;;
u)
MYSQL_USER=$OPTARG
;;
p)
MYSQL_PASS=$OPTARG
;;
d)
BACKUP_DIR=$OPTARG
;;
\?)
echo "Invalid option: -$OPTARG" >&2
exit 2;;
:)
echo "Option -$OPTARG requires an argument" >&2
exit 2;;
esac
done
shift $((OPTIND-1))
echo "MYSQL_HOST='$MYSQL_HOST' MYSQL_USER='$MYSQL_USER' MYSQL_PASS='$MYSQL_PASS' BACKUP_DIR='$BACKUP_DIR' Additionals: $@"
War bei solchen Ereignissen fehlgeschlagen ... ./command.sh -d -h
Wenn ich möchte, dass -d als Argument erforderlich markiert wird, aber ich erhalte, dessen Wert -d=-h
nicht das ist, was ich brauche.
Daher dachte ich, es wäre einfacher, meine eigene Validierung innerhalb der case-Anweisungen durchzuführen, um sicherzustellen, dass jede Option nur einmal festgelegt und festgelegt wird.
Ich versuche Folgendes zu tun, aber meine if [ ! "$MYSQL_HOST" ]; then
Blöcke werden nicht ausgelöst.
OPTIND=1 # Reset if getopts used previously
if (($# == 0)); then
echo "Usage"
exit 2
fi
while getopts ":h:u:p:d:" opt; do
case "$opt" in
h)
MYSQL_HOST=$OPTARG
if [ ! "$MYSQL_HOST" ]; then
echo "host not set"
exit 2
fi
;;
u)
MYSQL_USER=$OPTARG
if [ ! "$MYSQL_USER" ]; then
echo "username not set"
exit 2
fi
;;
p)
MYSQL_PASS=$OPTARG
if [ ! "$MYSQL_PASS" ]; then
echo "password not set"
exit 2
fi
;;
d)
BACKUP_DIR=$OPTARG
if [ ! "$BACKUP_DIR" ]; then
echo "backup dir not set"
exit 2
fi
;;
\?)
echo "Invalid option: -$OPTARG" >&2
exit 2;;
#:)
# echo "Option -$opt requires an argument" >&2
# exit 2;;
esac
done
shift $((OPTIND-1))
echo "MYSQL_HOST='$MYSQL_HOST' MYSQL_USER='$MYSQL_USER' MYSQL_PASS='$MYSQL_PASS' BACKUP_DIR='$BACKUP_DIR' Additionals: $@"
Gibt es einen Grund, warum ich nicht überprüfen kann, ob ein OPTARG
von innen eine Länge von Null hat getopts ... while ... case
?
Was ist der bessere Weg , mein eigenes Argument Validierung mit laufen getopts
in einem Fall , wo ich will auf das zu verlassen nicht :)
. Führen Sie meine Argumentvalidierung außerhalb des while ... case ... esac
?
Dann könnte ich mit Argumentwerten von -d
etc enden und keine fehlende Option abfangen.
while
Schleife über die Optionen läuft. Dies ist die Methode, mit der ich mich entschieden habe, obwohl sie im Vergleich zu anderen ausführlich ist, ist sehr klar, was im Skript vor sich geht. In diesem Fall ist die Wartbarkeit durch andere wichtig.Da die anderen Antworten Ihre Frage nicht so oft beantworten: Dies ist das erwartete Verhalten und basiert darauf, wie POSIX interpretiert wird:
Dies ist alles, was gesagt wird, und um es kurz zu machen:
getopts
Weiß nicht, dass das vollkommen gültige Argument, das es für die Option sieht, für die Sie ein Argument benötigen , eigentlich kein Optionsargument, sondern eine andere Option ist . Nichts hindert Sie daran,-h
ein gültiges Argument für die-d
Option zu haben. In der Praxis bedeutet dies, dassgetopts
nur dann ein Fehler ausgegeben wird, wenn Ihre Option, für die ein Argument erforderlich ist, als letztes in der Befehlszeile angezeigt wird, z.test.sh
::Beispiel:
Der Grund, warum Ihr zweiter Ansatz nicht funktioniert, liegt darin, dass die Analyse
getopts
immer noch dieselbe ist. Sobald Sie sich also in der Schleife befinden, ist der "Schaden" bereits angerichtet.Wenn Sie dies unbedingt verbieten möchten, müssen Sie, wie Benubird betonte, Ihre Optionsargumente selbst überprüfen und einen Fehler auslösen, wenn sie einer gültigen Option entsprechen.
quelle
Ich würde weiterhin verwenden,
getopts
aber einige zusätzliche Überprüfungen durchführen, nachdem: (ungetestet)erfordert Bash Version 4
quelle
Das in Gnu integrierte getopt ohne Shell erledigt weniger Arbeit für Sie, bietet jedoch mehr Flexibilität, da Sie bestimmen können, was passiert, nachdem ein Flag gefunden wurde, einschließlich des Verschiebens der Argumente selbst.
Ich habe einen Artikel gefunden , in dem getopts und getopt verglichen werden, was wahrscheinlich hilfreich sein wird, da das Handbuch (zumindest vor dem Kaffee) schwer zu verstehen ist.
quelle
Zunächst sollten Sie verwenden
if [ -z "$MYSQL_USER" ]
.Zweitens besteht keine Notwendigkeit für die Zuordnung -
if [ -z "$OPTARG" ]
wird gut funktionieren.Drittens vermute ich, was Sie tatsächlich wollen, ist
if [ ${#OPTARG} = 0 ]
. $ {# x} ist eine Bash-Sache, die die Länge der Zeichenfolge $ x zurückgibt (mehr dazu hier ).Viertens würde ich, wenn Sie Ihre eigene Validierung durchführen, getopt anstelle von getopts empfehlen, da dies viel mehr Flexibilität bietet.
Um Ihre erste Frage zu beantworten, können Sie schließlich feststellen, wann ein Flag als Argument übergeben wird, indem Sie eine Liste von Flags wie folgt oben einfügen:
Und dann überprüfen Sie die Option, bei der Sie überprüfen möchten, ob das angegebene Argument eine Option ist.
Keine perfekte Antwort, aber es funktioniert! Ihr Problem ist, dass "-h" ein vollkommen gültiges Argument ist und Sie der Shell keine Möglichkeit geben zu wissen, dass sie nur nach Parametern sucht, die keine gültigen Flags sind.
quelle