複数のオプションの名前付き引数を受け入れるには、batファイルが必要です。
mycmd.bat man1 man2 -username alice -otheroption
たとえば、私のコマンドには2つの必須パラメーターと、引数値がaliceである2つのオプションパラメーター(-username)、および-otheroptionがあります。
これらの値を変数に取り込めるようにしたいと思います。
すでにこれを解決した人に電話をかけるだけです。これらのバットファイルは苦痛です。
複数のオプションの名前付き引数を受け入れるには、batファイルが必要です。
mycmd.bat man1 man2 -username alice -otheroption
たとえば、私のコマンドには2つの必須パラメーターと、引数値がaliceである2つのオプションパラメーター(-username)、および-otheroptionがあります。
これらの値を変数に取り込めるようにしたいと思います。
すでにこれを解決した人に電話をかけるだけです。これらのバットファイルは苦痛です。
http://web.archive.org/web/20090403050231/http://www.pcguide.com/vb/showthread.php?t=52323
。
回答:
@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
SHIFT /2
引数2からシフトします。2回シフトしません。に置き換えるべきではありませんSHIFT & SHIFT
か?
mycmd.bat -username anyvalue -username myName -otheroption othervalue
。結果はuser = myName、other = othervalueになります。しかし、コードはuser = -username、other = othervalueを与えます。に置き換えることSHIFT /2
でバグが修正されましたSHIFT & SHIFT
。
;
ません-の代わりに使用することはできません&
。
%1
および%2
「使用」されています。b)SHIFT
11行目のシングルは、値を%2
1つ下に移動してから、(再び)として使用可能%1
になり、の「未使用」値は%3
として使用可能になります%2
。c)IF
行13には、このすでに「使用済み」の値が表示され、%2
そこから現在はになってい%1
ます。d)10行目の「user-name」がのよう"-otheroption"
に見える場合、それは再び使用other
され、%2
おそらく次のオプションの名前であるの新しい値に設定されます。--->
-otheroption
後に値が続かなかったため、おそらく-Flag
タイプオプションとして意図されており、2番目の引数を消費するべきではありません。3番目:引数%1
が内部IF
ステートメントによって処理されない場合、それは黙って無視されます。コードはおそらく、それが有効なオプションではなかったことを示すメッセージを表示するはずです。これは、requiredステートメントSHIFT
とGOTO :loop
ステートメントを内部IF
ステートメントに追加するか、ステートメントを追加することによって実行できますELSE
。
選択した回答は機能しますが、多少の改善が必要になる可能性があります。
私のソリューションは、すべてのオプションとそのデフォルトを定義するOPTIONS変数の作成に依存しています。OPTIONSは、指定されたオプションが有効かどうかをテストするためにも使用されます。オプションと同じ名前の変数にオプション値を格納するだけで、膨大な量のコードが節約されます。コードの量は、定義されているオプションの数に関係なく一定です。OPTIONS定義のみを変更する必要があります。
編集 -また、必須の位置引数の数が変更された場合は、:loopコードを変更する必要があります。たとえば、多くの場合、すべての引数に名前が付けられます。この場合、3ではなく位置1から始まる引数を解析する必要があります。したがって、:loop内では、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
引数1がで始まらないまで続きます/
/
。SET /VAR=VALUE
失敗しSET "/VAR=VALUE"
ます。とにかく、私はすでに私のソリューションでこれを行っています。/
。で始まる可能性がありません。この制限は//
、オプション解析ループを終了するためのシグナルとして機能する暗黙的に定義されたオプションを使用することで解消できます。//
「オプション」には何も保存されません。
更新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!
オプションの引数を使用したいが、名前付き引数を使用したくない場合は、このアプローチが役に立ちました。これは従うのがはるかに簡単なコードだと思います。
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%
IF "%1"==""
引数に引用符自体が含まれている場合は失敗します。代わりに、._ = []#などの他の非特殊記号を使用してください
長所
%1
、%2
...%*
タクトで/arg
と-arg
スタイルの両方で機能します短所
setlocal
、ローカルスコープに使用するか、付随する:CLEAR-ARGS
ルーチンを作成してください。--force
に-f
)""
引数のサポートはありません次の引数が.bat変数にどのように関連するかの例を次に示します。
>> testargs.bat /b 3 -c /d /e /f /g /h /i /j /k /bar 5 /foo "c:\"
echo %* | /b 3 -c /d /e /f /g /h /i /j /k /bar 5 /foo "c:\"
echo %ARG_FOO% | c:\
echo %ARG_A% |
echo %ARG_B% | 3
echo %ARG_C% | 1
echo %ARG_D% | 1
@echo off
setlocal
CALL :ARG-PARSER %*
::Print examples
echo: ALL: %*
echo: FOO: %ARG_FOO%
echo: A: %ARG_A%
echo: B: %ARG_B%
echo: C: %ARG_C%
echo: D: %ARG_C%
::*********************************************************
:: Parse commandline arguments into sane variables
:: See the following scenario as usage example:
:: >> thisfile.bat /a /b "c:\" /c /foo 5
:: >> CALL :ARG-PARSER %*
:: ARG_a=1
:: ARG_b=c:\
:: ARG_c=1
:: ARG_foo=5
::*********************************************************
:ARG-PARSER
::Loop until two consecutive empty args
:loopargs
IF "%~1%~2" EQU "" GOTO :EOF
set "arg1=%~1"
set "arg2=%~2"
shift
::Allow either / or -
set "tst1=%arg1:-=/%"
if "%arg1%" NEQ "" (
set "tst1=%tst1:~0,1%"
) ELSE (
set "tst1="
)
set "tst2=%arg2:-=/%"
if "%arg2%" NEQ "" (
set "tst2=%tst2:~0,1%"
) ELSE (
set "tst2="
)
::Capture assignments (eg. /foo bar)
IF "%tst1%" EQU "/" IF "%tst2%" NEQ "/" IF "%tst2%" NEQ "" (
set "ARG_%arg1:~1%=%arg2%"
GOTO loopargs
)
::Capture flags (eg. /foo)
IF "%tst1%" EQU "/" (
set "ARG_%arg1:~1%=1"
GOTO loopargs
)
goto loopargs
GOTO :EOF
:ARG-PARSER
ルーチンの内容を外部の.batファイルに移動して、arg-parser.bat
他のスクリプトでも使用できるようにすることもできます。
バッチファイルで短い(-h)、長い(--help)、およびオプション以外の引数を処理するプログラムを作成した後。この手法には次のものが含まれます。
非オプション引数の後にオプション引数が続きます。
'--help'のような引数を持たないオプションのシフト演算子。
引数を必要とするオプションの2つのタイムシフト演算子。
すべてのコマンドライン引数を処理するためにラベルをループします。
スクリプトを終了し、「-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
これが引数パーサーです。任意の文字列引数(変更されないまま)またはエスケープされたオプション(単一またはオプション/値のペア)を混在させることができます。それをテストするには、最後の2つのステートメントのコメントを外し、次のように実行します。
getargs anystr1 anystr2 /test$1 /test$2=123 /test$3 str anystr3
エスケープ文字はとして定義され"_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