Die ausgewählte Antwort funktioniert, könnte aber verbessert werden.
- Die Optionen sollten wahrscheinlich auf Standardwerte initialisiert werden.
- Es wäre schön,% 0 sowie die erforderlichen Argumente% 1 und% 2 beizubehalten.
- Es wird schwierig, für jede Option einen IF-Block zu haben, insbesondere wenn die Anzahl der Optionen zunimmt.
- Es wäre schön, eine einfache und präzise Möglichkeit zu haben, alle Optionen und Standardeinstellungen schnell an einem Ort zu definieren.
- Es wäre gut, eigenständige Optionen zu unterstützen, die als Flags dienen (kein Wert nach der Option).
- Wir wissen nicht, ob ein Argument in Anführungszeichen steht. Wir wissen auch nicht, ob ein arg-Wert mit maskierten Zeichen übergeben wurde. Es ist besser, mit% ~ 1 auf ein Argument zuzugreifen und die Zuweisung in Anführungszeichen zu setzen. Dann kann sich der Stapel auf das Fehlen von Anführungszeichen verlassen, aber Sonderzeichen sind im Allgemeinen immer noch sicher, ohne zu entkommen. (Dies ist nicht kugelsicher, aber es behandelt die meisten Situationen)
Meine Lösung basiert auf der Erstellung einer OPTIONS-Variablen, die alle Optionen und ihre Standardeinstellungen definiert. OPTIONEN wird auch verwendet, um zu testen, ob eine bereitgestellte Option gültig ist. Eine enorme Menge an Code wird gespeichert, indem die Optionswerte einfach in Variablen gespeichert werden, die den gleichen Namen wie die Option haben. Die Codemenge ist unabhängig von der Anzahl der definierten Optionen konstant. Nur die OPTIONS-Definition muss geändert werden.
BEARBEITEN - Außerdem muss sich der: -Schleifencode ändern, wenn sich die Anzahl der obligatorischen Positionsargumente ändert. Beispielsweise werden häufig alle Argumente benannt. In diesem Fall möchten Sie Argumente ab Position 1 anstelle von 3 analysieren. In der: -Schleife werden also alle 3 zu 1 und 4 zu 2.
@echo off
setlocal enableDelayedExpansion
:: Define the option names along with default values, using a <space>
:: delimiter between options. I'm using some generic option names, but
:: normally each option would have a meaningful name.
::
:: Each option has the format -name:[default]
::
:: The option names are NOT case sensitive.
::
:: Options that have a default value expect the subsequent command line
:: argument to contain the value. If the option is not provided then the
:: option is set to the default. If the default contains spaces, contains
:: special characters, or starts with a colon, then it should be enclosed
:: within double quotes. The default can be undefined by specifying the
:: default as empty quotes "".
:: NOTE - defaults cannot contain * or ? with this solution.
::
:: Options that are specified without any default value are simply flags
:: that are either defined or undefined. All flags start out undefined by
:: default and become defined if the option is supplied.
::
:: The order of the definitions is not important.
::
set "options=-username:/ -option2:"" -option3:"three word default" -flag1: -flag2:"
:: Set the default option values
for %%O in (%options%) do for /f "tokens=1,* delims=:" %%A in ("%%O") do set "%%A=%%~B"
:loop
:: Validate and store the options, one at a time, using a loop.
:: Options start at arg 3 in this example. Each SHIFT is done starting at
:: the first option so required args are preserved.
::
if not "%~3"=="" (
set "test=!options:*%~3:=! "
if "!test!"=="!options! " (
rem No substitution was made so this is an invalid option.
rem Error handling goes here.
rem I will simply echo an error message.
echo Error: Invalid option %~3
) else if "!test:~0,1!"==" " (
rem Set the flag option using the option name.
rem The value doesn't matter, it just needs to be defined.
set "%~3=1"
) else (
rem Set the option value using the option as the name.
rem and the next arg as the value
set "%~3=%~4"
shift /3
)
shift /3
goto :loop
)
:: Now all supplied options are stored in variables whose names are the
:: option names. Missing options have the default value, or are undefined if
:: there is no default.
:: The required args are still available in %1 and %2 (and %0 is also preserved)
:: For this example I will simply echo all the option values,
:: assuming any variable starting with - is an option.
::
set -
:: To get the value of a single parameter, just remember to include the `-`
echo The value of -username is: !-username!
Es gibt wirklich nicht so viel Code. Der größte Teil des obigen Codes besteht aus Kommentaren. Hier ist genau der gleiche Code ohne die Kommentare.
@echo off
setlocal enableDelayedExpansion
set "options=-username:/ -option2:"" -option3:"three word default" -flag1: -flag2:"
for %%O in (%options%) do for /f "tokens=1,* delims=:" %%A in ("%%O") do set "%%A=%%~B"
:loop
if not "%~3"=="" (
set "test=!options:*%~3:=! "
if "!test!"=="!options! " (
echo Error: Invalid option %~3
) else if "!test:~0,1!"==" " (
set "%~3=1"
) else (
set "%~3=%~4"
shift /3
)
shift /3
goto :loop
)
set -
:: To get the value of a single parameter, just remember to include the `-`
echo The value of -username is: !-username!
Diese Lösung bietet Argumente im Unix-Stil innerhalb eines Windows-Stapels. Dies ist nicht die Norm für Windows - Batch hat normalerweise die Optionen vor den erforderlichen Argumenten und den Optionen wird ein Präfix vorangestellt/
.
Die in dieser Lösung verwendeten Techniken lassen sich leicht an einen Windows-Optionsstil anpassen.
- Die Parsing-Schleife sucht immer nach einer Option bei
%1
und wird fortgesetzt, bis arg 1 nicht mit beginnt/
- Beachten Sie, dass SET-Zuweisungen in Anführungszeichen gesetzt werden müssen , wenn der Name mit beginnt
/
.
SET /VAR=VALUE
schlägt fehl
SET "/VAR=VALUE"
funktioniert. Ich mache das sowieso schon in meiner Lösung.
- Der Standard-Windows-Stil schließt die Möglichkeit aus, dass der erste erforderliche Argumentwert mit beginnt
/
. Diese Einschränkung kann beseitigt werden, indem eine implizit definierte //
Option verwendet wird, die als Signal zum Verlassen der Optionsanalyse-Schleife dient. Für die //
"Option" wird nichts gespeichert .
Update 28.12.2015: Unterstützung für !
In-Optionswerte
Im obigen Code wird jedes Argument erweitert, während die verzögerte Erweiterung aktiviert ist. Dies bedeutet, dass !
es höchstwahrscheinlich entfernt wird oder dass etwas Ähnliches !var!
erweitert wird. Darüber hinaus ^
kann auch abgestreift werden, wenn !
vorhanden. Die folgende kleine Änderung am nicht kommentierten Code hebt die Einschränkung auf, sodass !
und ^
in Optionswerten beibehalten werden.
@echo off
setlocal enableDelayedExpansion
set "options=-username:/ -option2:"" -option3:"three word default" -flag1: -flag2:"
for %%O in (%options%) do for /f "tokens=1,* delims=:" %%A in ("%%O") do set "%%A=%%~B"
:loop
if not "%~3"=="" (
set "test=!options:*%~3:=! "
if "!test!"=="!options! " (
echo Error: Invalid option %~3
) else if "!test:~0,1!"==" " (
set "%~3=1"
) else (
setlocal disableDelayedExpansion
set "val=%~4"
call :escapeVal
setlocal enableDelayedExpansion
for /f delims^=^ eol^= %%A in ("!val!") do endlocal&endlocal&set "%~3=%%A" !
shift /3
)
shift /3
goto :loop
)
goto :endArgs
:escapeVal
set "val=%val:^=^^%"
set "val=%val:!=^!%"
exit /b
:endArgs
set -
:: To get the value of a single parameter, just remember to include the `-`
echo The value of -username is: !-username!