批处理文件 - 命令行参数的数量

时间:2009-08-18 05:19:55

标签: shell batch-file scripting

只是将一些shell脚本转换为批处理文件,有一件事我似乎无法找到......这是对命令行参数数量的简单计算。

例如。如果你有:

myapp foo bar

在Shell中:

  • $# - > 2
  • $ * - > foo bar
  • $ 0 - > MyApp的
  • $ 1 - > FOO
  • $ 2 - >杆

批处理

  • ? - > 2< ----什么命令?!
  • %* - > foo bar
  • %0 - > MyApp的
  • %1 - > FOO
  • %2 - >杆

所以我环顾四周,要么我正在寻找错误的地方,要么我失明了,但我似乎无法找到一种方法来获取传入的命令行参数数量。< / p>

批处理文件是否有与shell的“$#”类似的命令?

PS。我发现的最接近的是遍历%1s并使用'shift',但是我需要在脚本后面引用%1,%2等,这样就不行了。

8 个答案:

答案 0 :(得分:89)

谷歌搜索可以从wikibooks获得以下结果:

set argC=0
for %%x in (%*) do Set /A argC+=1

echo %argC%

似乎cmd.exe已经从旧的DOS时代发展了一点:)

答案 1 :(得分:37)

您倾向于使用这种逻辑处理多个参数:

IF "%1"=="" GOTO HAVE_0
IF "%2"=="" GOTO HAVE_1
IF "%3"=="" GOTO HAVE_2

如果你有超过9个参数,那么你会对这种方法感到失望。有各种各样的黑客可以创建你可以找到here的计数器,但要警告这些不适合胆小的人。

答案 2 :(得分:18)

下面的函数: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"

答案 3 :(得分:7)

试试这个:

SET /A ARGS_COUNT=0    
FOR %%A in (%*) DO SET /A ARGS_COUNT+=1    
ECHO %ARGS_COUNT%

答案 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

答案 5 :(得分:2)

避免使用shiftfor周期,但会牺牲尺寸和可读性。

@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

编辑:这里使用的“技巧”包括:

  1. 使用包含百分号(%%)和a的字符串构造表示当前求值的命令行参数变量(即“%1”,“%2”等)的字符串每次循环迭代时计数器变量arg_idx

  2. 将该字符串存储到变量curr_arg_label

  3. 将该字符串(!curr_arg_label!)和返回变量的名称(curr_arg_value)传递给原始子程序get_value

  4. 在子程序中,它的第一个参数(%1)值用于赋值(set)的左侧,而它的第二个参数(%2)值用于右侧。但是,当第二个子程序的参数被传递时,它将被命令解释器解析为主程序的命令行参数的值。也就是说,传递的内容不是,例如,“%4”,而是第四个命令行参数变量保存的值(样本用法中的“another_arg”)。

  5. 然后测试给作为返回变量(curr_arg_value)的子程序的变量是否未定义,如果当前评估的命令行参数不存在则会发生这种情况。最初这是将方括号中包含的返回变量的值与空方括号进行比较(这是我知道测试程序或子程序参数的唯一方法,它可能包含引号并且是试错法阶段的一个被忽略的遗留物)但是从那时起就固定在现在的状态。

答案 6 :(得分:1)

最后一个答案是两年前,但是我需要一个用于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样式的变量。所有其他内容仅探测结果并显示转换为本地args。您可以在任何函数中按索引引用参数。

答案 7 :(得分:0)

一个可靠的解决方案是将计数委托给用call调用的子例程;子例程使用goto语句来模拟一个循环,在该循环中,shift用于迭代使用(仅子例程)参数:

@echo off
setlocal

:: Call the argument-counting subroutine with all arguments received,
:: without interfering with the ability to reference the arguments
:: with %1, ... later.
call :count_args %*

:: Print the result.
echo %ReturnValue% argument(s) received.

:: Exit the batch file.
exit /b

:: Subroutine that counts the arguments given.
:: Returns the count in %ReturnValue%
:count_args
  set /a ReturnValue = 0
  :count_args_for

    if %1.==. goto :eof

    set /a ReturnValue += 1

    shift
  goto count_args_for