いくつかのシェルスクリプトをバッチファイルに変換するだけで、見つけられないように思えることが1つあります。それは、コマンドライン引数の数の単純なカウントです。
例えば。あなたが持っている場合:
myapp foo bar
シェルで:
バッチで
だから私は周りを見回して、間違った場所を見ているか、盲目であるかのどちらかですが、渡されたコマンドライン引数の数を取得する方法を見つけることができないようです。
バッチファイル用のシェルの「$#」に似たコマンドはありますか?
追伸私が見つけた最も近い方法は、%1を反復処理し、 'shift'を使用することですが、スクリプト内で後で%1、%2などを参照する必要があるため、これは役に立ちません。
少しグーグルすると、 wikibooks から次の結果が得られます。
set argC=0
for %%x in (%*) do Set /A argC+=1
echo %argC%
Cmd.exeは古いDOS時代から少し進化したようです:)
この種のロジックでは、多くの引数を処理する傾向があります。
IF "%1"=="" GOTO HAVE_0
IF "%2"=="" GOTO HAVE_1
IF "%3"=="" GOTO HAVE_2
等.
あなたが9つ以上の引数を持っている場合、あなたはしかしこのアプローチで台無しにされています。カウンターを作成するためのさまざまなハックがありますが、これらは ここ で見つけることができますが、気弱な人向けではないことに注意してください。
関数 :getargc
以下はあなたが探しているものかもしれません。
@echo off
setlocal enableextensions enabledelayedexpansion
call :getargc argc %*
echo Count is %argc%
echo Args are %*
endlocal
goto :eof
:getargc
set getargc_v0=%1
set /a "%getargc_v0% = 0"
:getargc_l0
if not x%2x==xx (
shift
set /a "%getargc_v0% = %getargc_v0% + 1"
goto :getargc_l0
)
set getargc_v0=
goto :eof
基本的には、リストに対して一度(関数に対してローカルであるため、シフトがメインプログラムのリストに影響を与えないように)繰り返し、実行されるまでカウントします。
また、気の利いたトリックを使用して、関数によって設定される戻り変数の名前を渡します。
メインプログラムは、それを呼び出す方法を示し、引数がエコーされていないことを確認します:
C:\Here> xx.cmd 1 2 3 4 5
Count is 5
Args are 1 2 3 4 5
C:\Here> xx.cmd 1 2 3 4 5 6 7 8 9 10 11
Count is 11
Args are 1 2 3 4 5 6 7 8 9 10 11
C:\Here> xx.cmd 1
Count is 1
Args are 1
C:\Here> xx.cmd
Count is 0
Args are
C:\Here> xx.cmd 1 2 "3 4 5"
Count is 3
Args are 1 2 "3 4 5"
引数の数が正確な数(9以下)でなければならない場合、これはそれをチェックする簡単な方法です:
if "%2" == "" goto args_count_wrong
if "%3" == "" goto args_count_ok
:args_count_wrong
echo I need exactly two command line arguments
exit /b 1
:args_count_ok
これを試して:
SET /A ARGS_COUNT=0
FOR %%A in (%*) DO SET /A ARGS_COUNT+=1
ECHO %ARGS_COUNT%
サイズと読みやすさを犠牲にして、shift
またはfor
サイクルの使用を避けます。
@echo off
setlocal EnableExtensions EnableDelayedExpansion
set /a arg_idx=1
set "curr_arg_value="
:loop1
if !arg_idx! GTR 9 goto :done
set curr_arg_label=%%!arg_idx!
call :get_value curr_arg_value !curr_arg_label!
if defined curr_arg_value (
echo/!curr_arg_label!: !curr_arg_value!
set /a arg_idx+=1
goto :loop1
)
:done
set /a cnt=!arg_idx!-1
echo/argument count: !cnt!
endlocal
goto :eof
:get_value
(
set %1=%2
)
出力:
count_cmdline_args.bat testing more_testing arg3 another_arg
%1: testing
%2: more_testing
%3: arg3
%4: another_arg
argument count: 4
編集:ここで使用される「トリック」は次のとおりです。
各ループ反復でパーセント文字(%%
)とカウンター変数arg_idx
を含む文字列を使用して、現在評価されているコマンドライン引数変数(つまり、「%1」、「%2」など)を表す文字列を構築します。
その文字列を変数curr_arg_label
に保存します。
その文字列(!curr_arg_label!
)と戻り変数の名前(curr_arg_value
)の両方をプリミティブサブプログラムget_value
に渡します。
サブプログラムでは、最初の引数の(%1
)値が割り当ての左側(set
)で使用され、2番目の引数の(%2
)値が右側で使用されます。ただし、2番目のサブプログラムの引数が渡されると、コマンドインタープリターによってメインプログラムのコマンドライン引数の値に解決されます。つまり、渡されるのは、たとえば「%4」ではなく、4番目のコマンドライン引数変数が保持する値(サンプルの使用法では「another_arg」)です。
次に、戻り変数(curr_arg_value
)としてサブプログラムに与えられた変数が未定義であるかどうかがテストされます。これは、現在評価されているコマンドライン引数がない場合に発生します。最初は、角括弧で囲まれた戻り変数の値と空の角括弧との比較でした(引用符が含まれている可能性があり、試行錯誤段階から見落とされていたテストプログラムまたはサブプログラムの引数を知る唯一の方法です)以来、現在の状態に修正されました。
最後の答えは2年前ですが、9つ以上のコマンドライン引数のバージョンが必要でした。また別の可能性があります...
@echo off
setlocal
set argc_=1
set arg0_=%0
set argv_=
:_LOOP
set arg_=%1
if defined arg_ (
set arg%argc_%_=%1
set argv_=%argv_% %1
set /a argc_+=1
shift
goto _LOOP
)
::dont count arg0
set /a argc_-=1
echo %argc_% arg(s)
for /L %%i in (0,1,%argc_%) do (
call :_SHOW_ARG arg%%i_ %%arg%%i_%%
)
echo converted to local args
call :_LIST_ARGS %argv_%
exit /b
:_LIST_ARGS
setlocal
set argc_=0
echo arg0=%0
:_LOOP_LIST_ARGS
set arg_=%1
if not defined arg_ exit /b
set /a argc_+=1
call :_SHOW_ARG arg%argc_% %1
shift
goto _LOOP_LIST_ARGS
:_SHOW_ARG
echo %1=%2
exit /b
解決策は最初の19行であり、すべての引数をcのようなスタイルの変数に変換します。他のすべてのものは結果をプローブし、ローカル引数への変換を示します。任意の関数でインデックスを使用して引数を参照できます。