Windows バッチが ks なことは今さら言うまでもないが、最もお手軽な手段であることも事実。特にユーザーに配布して実行させたい場合、環境の差異を気にしないくて良いのは何にも勝る利点だ。同様の意味で WSH も素晴らしいが、結果が同じならよりシンプルな方を選びたい。
という訳で私はよくバッチも書くが、ちょっと凝ったバッチを書こうとしたとき、オプション処理にはいつも悩まされる。きちんとやろうとすると面倒だし、どうせならこの手の処理は共通化したい。誰か getopt みたいなやつ作ってねーのかよ、と偶にググってみても、これといったものが見つかった試しがない。
まあ、もしバッチでできたらとっくに誰か作ってるよねー、と今までは諦めていたのだが、今回ふと思って試してみた。
test.bat:
@echo off
setlocal
set opt=hoge
set opt_%opt%=HOGE
echo opt_hoge=%opt_hoge%
>test.bat
opt_hoge=HOGE
え!? set の左辺で変数展開できちゃうの?
そうか、set もコマンドだから、引数中の変数は展開されてから set に渡るのか。ていうか、これ使えば getopt できるんじゃね?
getopt.cmd:
@echo off
if not "%~1"=="/?" goto :main
echo.Usage:
echo. call %~nx0 [/OPTION[:VALUE]]...
echo.
echo.Description:
echo. Parse options and define 'OPT_^<OPTION^>' variables, and set 'OPTIND' as
echo. the number of processed arguments.
echo.
echo.Exsample:
echo. When a batch file is invoked with arguments,
echo.
echo. ^>example.bat /foo /bar:BAR /baz:"B A Z" arg1 arg2 ...
echo.
echo. In the batch file, a typical usage is:
echo.
echo. call %~nx0 %%*
echo. for /L %%%%i in (1,1,%%OPTIND%%) do shift /1
echo.
echo. Then a boolean option '/foo' can be tested as below.
echo.
echo. if defined OPT_FOO ^(
echo. echo /foo was given
echo. ^) else ^(
echo. echo /foo was not given
echo. ^)
echo.
echo. Other options have a value can be used as regular variable.
echo.
echo. echo bar=%%OPT_BAR%%
echo. echo baz=%%OPT_BAZ%%
echo.
echo. Remaining arguments are referred through batch parameter.
echo.
echo. echo args=%%1 %%2 %%3 %%4 %%5 %%6 %%7 %%8 %%9
echo.
echo. Note that '%%*' batch parameter is never updated by 'shift'.
exit /b 1
:main
set OPTIND=0
:_loop_args
set _getopt_arg=%1
if defined _getopt_arg (
call :parse_arg %_getopt_arg%
if not errorlevel 1 (
shift /1
set /a OPTIND+=1
goto :_loop_args
)
)
set _getopt_arg=
set _getopt_opt=
set _getopt_value=
set _getopt_bool=
exit /b 0
:parse_arg
set _getopt_opt=
set _getopt_value=%~1
set _getopt_bool=1
if not "%_getopt_value:~0,1%"=="/" goto :_parse_arg_ret
set _getopt_value=%_getopt_value:~1%
:_loop_arg_chars
if not defined _getopt_value goto :_parse_arg_ret
if "%_getopt_value:~0,1%"==":" (
set _getopt_bool=
set _getopt_value=%_getopt_value:~1%
goto :_parse_arg_ret
) else (
set _getopt_opt=%_getopt_opt%%_getopt_value:~0,1%
set _getopt_value=%_getopt_value:~1%
)
goto :_loop_arg_chars
:_parse_arg_ret
if not defined _getopt_opt exit /b 1
if defined _getopt_bool (
call :set_opt %_getopt_opt% %_getopt_bool%
) else (
call :set_opt %_getopt_opt% %_getopt_value%
)
exit /b 0
:set_opt
set OPT_%1=%~2
exit /b 0
できちゃった :-D。使い方は次の通り。
test_getopt.bat:
@echo off
setlocal
call getopt.cmd %*
for /L %%i in (1,1,%optind%) do shift /1
if defined opt_hoge echo /hoge was given
if not defined opt_hage echo /hage was not given
echo /piyo=%opt_piyo%
echo /fuga=%opt_fuga%
echo /boke=%opt_boke%
echo %1 %2 %3 %4 %5 %6 %7 %8 %9
>test_getopt.bat /hoge /piyo:PIYO /fuga:"FU GA" /boke: arg1 arg2 ...
/hoge was given
/hage was not given
/piyo=PIYO
/fuga=FU GA
/boke=
arg1 arg2 ...
まだ改良の余地はあると思うが、私が使うには当面これで十分。
ところで今回の件で、Windows バッチは変数名に記号(どころか空白も!)を使えることを知ったが、ならば getopt.cmd に /? を渡せば変数 opt_? を定義してくれそうに思う。しかしそれは叶わない。
>call getopt.cmd /?
バッチ プログラムを別のバッチ プログラムから呼び出します。
CALL [ドライブ:][パス]ファイル名 [バッチパラメーター]
バッチパラメーター バッチ プログラムで必要なコマンド ライン情報を指定します。
コマンド拡張機能を有効にすると、CALL は次のように変更されます:
<...snip...>
call が /? を奪い取る模様。やっぱ Windows バッチって ks だわ。
0 件のコメント:
コメントを投稿
注: コメントを投稿できるのは、このブログのメンバーだけです。