Câu trả lời đã chọn hoạt động, nhưng nó có thể sử dụng một số cải tiến.
- Các tùy chọn có thể nên được khởi tạo thành các giá trị mặc định.
- Sẽ rất tốt nếu giữ nguyên% 0 cũng như các args yêu cầu% 1 và% 2.
- Việc có một khối IF cho mọi tùy chọn trở nên khó khăn, đặc biệt là khi số lượng tùy chọn ngày càng tăng.
- Sẽ thật tuyệt nếu có một cách đơn giản và ngắn gọn để nhanh chóng xác định tất cả các tùy chọn và mặc định ở một nơi.
- Sẽ rất tốt nếu hỗ trợ các tùy chọn độc lập đóng vai trò là cờ (không có giá trị nào theo sau tùy chọn).
- Chúng tôi không biết liệu một đối số có được đặt trong dấu ngoặc kép hay không. Chúng tôi cũng không biết liệu một giá trị đối số có được chuyển bằng cách sử dụng các ký tự thoát hay không. Tốt hơn nên truy cập vào một đối số bằng cách sử dụng% ~ 1 và đặt phần gán trong dấu ngoặc kép. Sau đó, lô có thể dựa vào việc không có dấu ngoặc kép đi kèm, nhưng các ký tự đặc biệt nói chung vẫn an toàn mà không bị thoát. (Đây không phải là chống đạn, nhưng nó xử lý hầu hết các tình huống)
Giải pháp của tôi dựa vào việc tạo một biến OPTIONS xác định tất cả các tùy chọn và giá trị mặc định của chúng. OPTIONS cũng được sử dụng để kiểm tra xem một tùy chọn được cung cấp có hợp lệ hay không. Một lượng lớn mã được lưu bằng cách lưu trữ các giá trị tùy chọn trong các biến có tên giống như tùy chọn. Số lượng mã là không đổi bất kể có bao nhiêu tùy chọn được xác định; chỉ có định nghĩa OPTIONS phải thay đổi.
CHỈNH SỬA - Ngoài ra, mã vòng lặp: phải thay đổi nếu số lượng các đối số vị trí bắt buộc thay đổi. Ví dụ: thường thì tất cả các đối số đều được đặt tên, trong trường hợp đó bạn muốn phân tích cú pháp các đối số bắt đầu từ vị trí 1 thay vì 3. Vì vậy, trong vòng lặp:, cả 3 trở thành 1 và 4 trở thành 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!
Thực sự không có nhiều mã. Hầu hết đoạn mã trên là bình luận. Đây là mã chính xác, không có bình luận.
@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!
Giải pháp này cung cấp các đối số kiểu Unix trong một lô Windows. Đây không phải là tiêu chuẩn cho Windows - hàng loạt thường có các tùy chọn đứng trước các đối số bắt buộc và các tùy chọn được đặt trước /
.
Các kỹ thuật được sử dụng trong giải pháp này có thể dễ dàng điều chỉnh cho các tùy chọn kiểu Windows.
- Vòng lặp phân tích cú pháp luôn tìm kiếm một tùy chọn tại
%1
và nó tiếp tục cho đến khi đối số 1 không bắt đầu bằng/
- Lưu ý rằng các phép gán SET phải được đặt trong dấu ngoặc kép nếu tên bắt đầu bằng
/
.
SET /VAR=VALUE
không
SET "/VAR=VALUE"
hoạt động. Tôi vẫn đang làm điều này trong giải pháp của mình.
- Kiểu Windows tiêu chuẩn loại trừ khả năng có giá trị đối số bắt buộc đầu tiên bắt đầu bằng
/
. Hạn chế này có thể được loại bỏ bằng cách sử dụng một //
tùy chọn được xác định ngầm đóng vai trò như một tín hiệu để thoát khỏi vòng lặp phân tích cú pháp tùy chọn. Không có gì sẽ được lưu trữ cho //
"tùy chọn".
Cập nhật 2015-12-28: Hỗ trợ !
giá trị trong tùy chọn
Trong đoạn mã trên, mỗi đối số được mở rộng trong khi bật tính năng mở rộng bị trì hoãn, có nghĩa là đối số đó !
rất có thể bị loại bỏ hoặc một cái gì đó tương tự !var!
được mở rộng. Ngoài ra, ^
cũng có thể bị tước nếu !
có. Sửa đổi nhỏ sau đây đối với mã chưa được chú thích sẽ loại bỏ giới hạn đó !
và ^
được giữ nguyên trong các giá trị tùy chọn.
@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!