选定的答案是有效的,但它可能需要一些改进。
-
选项可能应初始化为默认值。
-
最好保留%0以及所需的参数%1和%2。
-
每个选项都有一个if块会让人很痛苦,特别是随着选项数量的增加。
-
最好有一种简单而简洁的方法在一个地方快速定义所有选项和默认值。
-
最好支持作为标志的独立选项(选项后面没有值)。
-
我们不知道arg是否用引号括起来。我们也不知道是否使用转义字符传递了arg值。最好使用%~1访问一个arg,并用引号括起来。然后,批处理可以依赖于没有括起来的引号,但是特殊字符在没有转义的情况下仍然是安全的。(这不是防弹的,但可以处理大多数情况)
我的解决方案依赖于创建一个选项变量,该变量定义所有选项及其默认值。选项还用于测试提供的选项是否有效。只需将选项值存储在与选项同名的变量中,就可以节省大量代码。不管定义了多少个选项,代码量都是常量;只有选项定义必须更改。
编辑
-此外,如果强制位置参数的数目发生更改,则:循环代码必须更改。例如,通常情况下,所有参数都是命名的,在这种情况下,您希望解析从位置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!
此解决方案在Windows批处理中提供Unix样式的参数。这不是Windows的规范-批处理通常在所需参数之前具有选项,并且选项的前缀为
/
.
此解决方案中使用的技术很容易适应Windows样式的选项。
-
解析循环总是在
%1
,然后继续,直到arg 1不以开头
/
-
注意设置工作分配
必须
如果名称以
/
.
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!