La risposta selezionata funziona, ma potrebbe essere migliorata.
- Le opzioni dovrebbero probabilmente essere inizializzate ai valori predefiniti.
- Sarebbe bello conservare% 0 così come gli argomenti obbligatori% 1 e% 2.
- Diventa un problema avere un blocco IF per ogni opzione, soprattutto quando il numero di opzioni cresce.
- Sarebbe bello avere un modo semplice e conciso per definire rapidamente tutte le opzioni e le impostazioni predefinite in un unico posto.
- Sarebbe utile supportare opzioni autonome che fungono da flag (nessun valore dopo l'opzione).
- Non sappiamo se un argomento è racchiuso tra virgolette. Né sappiamo se un valore arg è stato passato utilizzando caratteri di escape. È meglio accedere a un argomento utilizzando% ~ 1 e racchiudere l'assegnazione tra virgolette. Quindi il batch può fare affidamento sull'assenza di virgolette racchiuse, ma i caratteri speciali sono ancora generalmente sicuri senza sfuggire. (Questo non è a prova di proiettile, ma gestisce la maggior parte delle situazioni)
La mia soluzione si basa sulla creazione di una variabile OPTIONS che definisce tutte le opzioni e le loro impostazioni predefinite. OPTIONS viene utilizzato anche per verificare se un'opzione fornita è valida. Un'enorme quantità di codice viene salvata semplicemente memorizzando i valori delle opzioni in variabili denominate come l'opzione. La quantità di codice è costante indipendentemente dal numero di opzioni definite; solo la definizione delle OPZIONI deve cambiare.
EDIT - Inoltre, il codice: loop deve cambiare se cambia il numero di argomenti posizionali obbligatori. Ad esempio, spesso viene assegnato un nome a tutti gli argomenti, nel qual caso si desidera analizzare gli argomenti che iniziano alla posizione 1 anziché 3. Quindi all'interno del ciclo:, tutti e 3 diventano 1 e 4 diventa 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!
Non c'è davvero molto codice. La maggior parte del codice sopra è un commento. Ecco lo stesso identico codice, senza i commenti.
@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!
Questa soluzione fornisce argomenti in stile Unix all'interno di un batch di Windows. Questa non è la norma per Windows: batch di solito ha le opzioni che precedono gli argomenti richiesti e le opzioni hanno il prefisso/ .
Le tecniche utilizzate in questa soluzione possono essere facilmente adattate per uno stile di opzioni Windows.
- Il ciclo di analisi cerca sempre un'opzione in
%1e continua finché arg 1 non inizia con/
- Notare che le assegnazioni SET devono essere racchiuse tra virgolette se il nome inizia con
/.
SET /VAR=VALUEnon riesce
SET "/VAR=VALUE" . Lo sto già facendo comunque nella mia soluzione.
- Lo stile standard di Windows preclude la possibilità che il primo valore dell'argomento richiesto inizi con
/. Questa limitazione può essere eliminata impiegando //un'opzione definita implicitamente che funge da segnale per uscire dal ciclo di analisi delle opzioni. Niente verrebbe memorizzato per l ' //"opzione".
Aggiornamento 2015-12-28: supporto per i !valori delle opzioni
Nel codice precedente, ogni argomento viene espanso mentre è abilitata l'espansione ritardata, il che significa che !molto probabilmente vengono rimossi, oppure qualcosa di simile !var!viene espanso. Inoltre, ^può anche essere spogliato se !presente. La seguente piccola modifica al codice non commentato rimuove la limitazione in modo tale che !e ^siano conservati nei valori delle opzioni.
@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!