La réponse choisie fonctionne, mais elle pourrait nécessiter une certaine amélioration.
- Les options devraient probablement être initialisées aux valeurs par défaut.
- Ce serait bien de conserver% 0 ainsi que les arguments requis% 1 et% 2.
- Cela devient pénible d'avoir un bloc IF pour chaque option, d'autant plus que le nombre d'options augmente.
- Ce serait bien d'avoir un moyen simple et concis de définir rapidement toutes les options et valeurs par défaut en un seul endroit.
- Il serait bon de prendre en charge les options autonomes qui servent d'indicateurs (aucune valeur après l'option).
- Nous ne savons pas si un argument est entre guillemets. Nous ne savons pas non plus si une valeur arg a été transmise à l'aide de caractères d'échappement. Mieux vaut accéder à un argument en utilisant% ~ 1 et mettre l'affectation entre guillemets. Ensuite, le lot peut s'appuyer sur l'absence de guillemets, mais les caractères spéciaux sont toujours généralement sûrs sans échapper. (Ce n'est pas à l'épreuve des balles, mais il gère la plupart des situations)
Ma solution repose sur la création d'une variable OPTIONS qui définit toutes les options et leurs valeurs par défaut. OPTIONS est également utilisé pour tester si une option fournie est valide. Une énorme quantité de code est enregistrée en stockant simplement les valeurs d'option dans des variables nommées de la même manière que l'option. La quantité de code est constante quel que soit le nombre d'options définies; seule la définition OPTIONS doit changer.
EDIT - De plus, le code de la boucle: doit changer si le nombre d'arguments de position obligatoires change. Par exemple, souvent, tous les arguments sont nommés, auquel cas vous voulez analyser les arguments commençant à la position 1 au lieu de 3. Ainsi, dans la boucle:, tous les 3 deviennent 1 et 4 devient 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!
Il n'y a vraiment pas beaucoup de code. La plupart des codes ci-dessus sont des commentaires. Voici exactement le même code, sans les commentaires.
@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!
Cette solution fournit des arguments de style Unix dans un lot Windows. Ce n'est pas la norme pour Windows - batch a généralement les options précédant les arguments requis et les options sont préfixées avec /
.
Les techniques utilisées dans cette solution sont facilement adaptées à un style d'options Windows.
- La boucle d'analyse recherche toujours une option à
%1
, et continue jusqu'à ce que arg 1 ne commence pas par/
- Notez que les affectations SET doivent être placées entre guillemets si le nom commence par
/
.
SET /VAR=VALUE
échoue
SET "/VAR=VALUE"
fonctionne. Je fais déjà cela dans ma solution de toute façon.
- Le style Windows standard exclut la possibilité que la première valeur d'argument requise commence par
/
. Cette limitation peut être éliminée en employant une //
option implicitement définie qui sert de signal pour quitter la boucle d'analyse des options. Rien ne serait stocké pour //
"l'option".
Mise à jour 28/12/2015: Prise en charge de!
en valeurs d'option
Dans le code ci-dessus, chaque argument est développé tandis que l'expansion retardée est activée, ce qui signifie qu'il !
est probablement supprimé, ou bien quelque chose comme !var!
est développé. En outre, ^
peut également être dépouillé s'il !
est présent. La petite modification suivante du code non commenté supprime la limitation telle que !
et ^
sont conservés dans les valeurs d'option.
@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!