Параметр опционального анализа файлов Windows Bat
Мне нужен мой bat файл, чтобы принимать несколько необязательных именованных аргументов.
mycmd.bat man1 man2 -username alice -otheroption
Например, моя команда имеет 2 обязательных параметра и два необязательных параметра (-имя), которые имеют значение аргумента alice и -theroption:
Я бы хотел, чтобы эти значения были привязаны к переменным.
Просто позвонив всем, кто уже решил это. Человеку эти файлы летучей мыши больно.
Ответы
Ответ 1
Хотя я склонен согласиться с комментарием @AlekDavis, тем не менее есть несколько способов сделать это в оболочке NT.
Подходом я бы воспользовался командой SHIFT и условным ветвлением IF, что-то вроде этого...
@ECHO OFF
SET man1=%1
SET man2=%2
SHIFT & SHIFT
:loop
IF NOT "%1"=="" (
IF "%1"=="-username" (
SET user=%2
SHIFT
)
IF "%1"=="-otheroption" (
SET other=%2
SHIFT
)
SHIFT
GOTO :loop
)
ECHO Man1 = %man1%
ECHO Man2 = %man2%
ECHO Username = %user%
ECHO Other option = %other%
REM ...do stuff here...
:theend
Ответ 2
Выбранный ответ работает, но он может использовать некоторое улучшение.
- Параметры, вероятно, должны быть инициализированы значениями по умолчанию.
- Было бы неплохо сохранить% 0, а также необходимые аргументы% 1 и% 2.
- Становится больно иметь блок IF для каждого параметра, особенно по мере увеличения количества вариантов.
- Было бы неплохо иметь простой и сжатый способ быстро определить все параметры и значения по умолчанию в одном месте.
- Было бы полезно поддерживать автономные параметры, которые служат флажками (без значения после значения).
- Мы не знаем, включен ли arg в кавычки. Мы также не знаем, было ли передано значение arg с использованием экранированных символов. Лучше получить доступ к аргументу, используя% ~ 1, и заключить присвоение в кавычки. Тогда партия может полагаться на отсутствие закрытых кавычек, но специальные символы по-прежнему в целом безопасны без выхода. (Это не доказательство пули, но оно справляется с большинством ситуаций).
Мое решение основывается на создании переменной OPTIONS, которая определяет все параметры и их значения по умолчанию. ОПЦИИ также используются для проверки того, действительна ли опция поставки. Огромный объем кода сохраняется, просто сохраняя значения параметра в переменных, названных так же, как и параметр. Объем кода постоянный независимо от того, сколько опций определено; только определение 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
, и он продолжается до тех пор, пока arg 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!
Ответ 3
Если вы хотите использовать необязательные аргументы, но не названные аргументы, то этот подход работал у меня. Я думаю, что для этого гораздо проще использовать код.
REM Get argument values. If not specified, use default values.
IF "%1"=="" ( SET "DatabaseServer=localhost" ) ELSE ( SET "DatabaseServer=%1" )
IF "%2"=="" ( SET "DatabaseName=MyDatabase" ) ELSE ( SET "DatabaseName=%2" )
REM Do work
ECHO Database Server = %DatabaseServer%
ECHO Database Name = %DatabaseName%
Ответ 4
Вот парсер аргументов. Вы можете смешивать любые строковые аргументы (оставленные без изменений) или экранированные опции (одиночные пары или пары опций/значений). Чтобы проверить это, раскомментируйте последние 2 утверждения и выполните следующее:
getargs anystr1 anystr2 /test$1 /test$2=123 /test$3 str anystr3
Escape-символ определяется как "_SEP_=/"
, переопределите, если необходимо.
@echo off
REM Command line argument parser. Format (both "=" and "space" separators are supported):
REM anystring1 anystring2 /param1 /param2=value2 /param3 value3 [...] anystring3 anystring4
REM Returns enviroment variables as:
REM param1=1
REM param2=value2
REM param3=value3
REM Leading and traling strings are preserved as %1, %2, %3 ... %9 parameters
REM but maximum total number of strings is 9 and max number of leading strings is 8
REM Number of parameters is not limited!
set _CNT_=1
set _SEP_=/
:PARSE
if %_CNT_%==1 set _PARAM1_=%1 & set _PARAM2_=%2
if %_CNT_%==2 set _PARAM1_=%2 & set _PARAM2_=%3
if %_CNT_%==3 set _PARAM1_=%3 & set _PARAM2_=%4
if %_CNT_%==4 set _PARAM1_=%4 & set _PARAM2_=%5
if %_CNT_%==5 set _PARAM1_=%5 & set _PARAM2_=%6
if %_CNT_%==6 set _PARAM1_=%6 & set _PARAM2_=%7
if %_CNT_%==7 set _PARAM1_=%7 & set _PARAM2_=%8
if %_CNT_%==8 set _PARAM1_=%8 & set _PARAM2_=%9
if "%_PARAM2_%"=="" set _PARAM2_=1
if "%_PARAM1_:~0,1%"=="%_SEP_%" (
if "%_PARAM2_:~0,1%"=="%_SEP_%" (
set %_PARAM1_:~1,-1%=1
shift /%_CNT_%
) else (
set %_PARAM1_:~1,-1%=%_PARAM2_%
shift /%_CNT_%
shift /%_CNT_%
)
) else (
set /a _CNT_+=1
)
if /i %_CNT_% LSS 9 goto :PARSE
set _PARAM1_=
set _PARAM2_=
set _CNT_=
rem getargs anystr1 anystr2 /test$1 /test$2=123 /test$3 str anystr3
rem set | find "test$"
rem echo %1 %2 %3 %4 %5 %6 %7 %8 %9
:EXIT
Ответ 5
Как только я написал программу, которая обрабатывает короткие (-h), long (--help) и необязательные аргументы в пакетном файле.
Эти методы включают в себя:
-
аргументы без опций, за которыми следуют аргументы параметров.
-
оператор смены для тех опций, у которых нет аргументов типа "-help".
-
два оператора сдвига по времени для тех параметров, которые требуют аргумента.
-
проведите по метке для обработки всех аргументов командной строки.
-
Выйдите из script и прекратите обработку для тех параметров, которые не требуют дополнительных действий, таких как "-help".
-
Написал справочные функции для удобства пользователя
Вот мой код.
set BOARD=
set WORKSPACE=
set CFLAGS=
set LIB_INSTALL=true
set PREFIX=lib
set PROGRAM=install_boards
:initial
set result=false
if "%1" == "-h" set result=true
if "%1" == "--help" set result=true
if "%result%" == "true" (
goto :usage
)
if "%1" == "-b" set result=true
if "%1" == "--board" set result=true
if "%result%" == "true" (
goto :board_list
)
if "%1" == "-n" set result=true
if "%1" == "--no-lib" set result=true
if "%result%" == "true" (
set LIB_INSTALL=false
shift & goto :initial
)
if "%1" == "-c" set result=true
if "%1" == "--cflag" set result=true
if "%result%" == "true" (
set CFLAGS=%2
if not defined CFLAGS (
echo %PROGRAM%: option requires an argument -- 'c'
goto :try_usage
)
shift & shift & goto :initial
)
if "%1" == "-p" set result=true
if "%1" == "--prefix" set result=true
if "%result%" == "true" (
set PREFIX=%2
if not defined PREFIX (
echo %PROGRAM%: option requires an argument -- 'p'
goto :try_usage
)
shift & shift & goto :initial
)
:: handle non-option arguments
set BOARD=%1
set WORKSPACE=%2
goto :eof
:: Help section
:usage
echo Usage: %PROGRAM% [OPTIONS]... BOARD... WORKSPACE
echo Install BOARD to WORKSPACE location.
echo WORKSPACE directory doesn't already exist!
echo.
echo Mandatory arguments to long options are mandatory for short options too.
echo -h, --help display this help and exit
echo -b, --boards inquire about available CS3 boards
echo -c, --cflag=CFLAGS making the CS3 BOARD libraries for CFLAGS
echo -p. --prefix=PREFIX install CS3 BOARD libraries in PREFIX
echo [lib]
echo -n, --no-lib don't install CS3 BOARD libraries by default
goto :eof
:try_usage
echo Try '%PROGRAM% --help' for more information
goto :eof