Вибрана відповідь працює, але вона може використати певні покращення.
- Можливо, параметри слід ініціалізувати до значень за замовчуванням.
- Було б непогано зберегти% 0, а також необхідні аргументи% 1 та% 2.
- Наявно болісно мати блок IF для кожного варіанту, особливо зі збільшенням кількості варіантів.
- Було б непогано мати простий і стислий спосіб швидкого визначення всіх параметрів та стандартних налаштувань в одному місці.
- Було б непогано підтримувати автономні опції, які слугують прапорами (значення не слід після опції).
- Ми не знаємо, чи аргумент укладено в лапки. Також ми не знаємо, чи було передано значення аргументу з використанням екранованих символів. Краще отримати доступ до аргументу за допомогою% ~ 1 і вкласти призначення у лапки. Тоді пакет може розраховувати на відсутність огороджувальних лапок, але спеціальні символи все ще безпечні, не виходячи з екрана. (Це не кульковий доказ, але він обробляє більшість ситуацій)
Моє рішення покладається на створення змінної OPTIONS, яка визначає всі параметри та значення за замовчуванням. ОПЦІЇ також використовуються для перевірки того, чи дійсна надана опція. Величезна кількість коду зберігається шляхом простого зберігання значень опцій у змінних, названих такими самими, як опція. Кількість коду є постійною, незалежно від того, скільки параметрів визначено; має змінитися лише визначення ВАРІАНТІВ.
EDIT - Крім того, код циклу: повинен змінюватися, якщо кількість обов'язкових позиційних аргументів змінюється. Наприклад, часто всі аргументи називаються, і в цьому випадку потрібно проаналізувати аргументи, що починаються з позиції 1 замість 3. Отже, у циклі: всі 3 стають 1, а 4 стають 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!
Коду насправді не так багато. Більшість коду вище - це коментарі. Ось точно такий самий код, без коментарів.
@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!
Це рішення надає аргументи стилю Unix у пакеті Windows. Це не є нормою для Windows - пакет, як правило, має параметри, що передують необхідним аргументам, і параметри мають префікс /.
Методи, що використовуються у цьому рішенні, легко адаптуються до параметрів у стилі Windows.
- Цикл розбору завжди шукає варіант на
%1, і він триває до тих пір, поки аргумент 1 не почнеться з/
- Зверніть увагу, що призначення SET слід укладати в лапки, якщо назва починається з
/.
SET /VAR=VALUEне
SET "/VAR=VALUE"працює. Я все одно роблю це у своєму рішенні.
- Стандартний стиль Windows виключає можливість першого необхідного значення аргументу, починаючи з
/. Це обмеження можна усунути, використовуючи неявно визначену //опцію, яка служить сигналом для виходу з циклу розбору опцій. Нічого не буде збережено для //"опції".
Оновлення 2015-12-28: Підтримка !значень опцій
У наведеному вище коді кожен аргумент розгортається, у той час як увімкнено відкладене розширення, а це означає, що !, швидше за все, розібрано, або ще щось подібне !var!розширено. Крім того, ^їх також можна позбавити, якщо вони !є. Наступні невеликі зміни в ун-коментував коди знімає обмеження таких , що !і ^зберігаються в значеннях опцій.
@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!