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


99

只是将一些shell脚本转换成批处理文件,我似乎找不到一件事...那就是对命令行参数数量的简单计数。

例如。如果你有:

myapp foo bar

在Shell中:

  • $#-> 2
  • $ *-> foo bar
  • $ 0-> myapp
  • $ 1-> foo
  • $ 2->酒吧

分批

  • ?? -> 2 <----什么命令?
  • %*-> foo栏
  • %0-> myapp
  • %1-> foo
  • %2->条

所以我环顾四周,或者我找错了地方,或者我瞎了眼,但是我似乎找不到找到传递传入的命令行参数数量的方法。

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

ps。我发现最接近的方法是遍历%1s并使用'shift',但是我稍后需要在脚本中引用%1,%2等,所以这样做不好。


你的绳子是2 myapp foo bar
PsychoData 2014年

2
建议:不要将sh转换为BAT。而是下载cygwin并使用它。即您的sh脚本将在Windows计算机上运行。而且您不必将所有sh都转换为BAT!
马蒂·麦高恩

Answers:


104

仔细搜索一下,您会从Wikibooks中获得以下结果:

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

echo %argC%

似乎cmd.exe从DOS时代起就有所发展:)


7
请注意,此变体for仅适用于看起来像文件名的参数,而不适用于诸如的选项字符串-?for %%i in ("%*") ...对于引号,使用引号()类似,-?但由于嵌套引号,对于引号使用引数()仍然失败。唯一可靠的方法似乎涉及shift……
Ferdinand Beyer

1
MyBatchFile "*.*" "Abc"报告argC == 9。
BrainSlugs83

已经测试了作为函数的2500个参数,并使用它来定义了相同大小的数组。不要问我为什么。多数情况下,只是了解什么批次能够完成。
T3RR0R

44

您倾向于使用这种逻辑来处理大量参数:

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

等等

如果您有9个以上的参数,那么您会迷上这种方法。您可以在此处找到各种用于创建计数器的技巧,但请注意,这些技巧不是针对胆小者。


6
您仍然可以使用shift超过9 ...的数量进行计数,而不必使用10行相等外观的代码。
乔伊,

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"

您如何基于此更改流量?(可能是一个不同的问题,但是我认为这里的一个简短示例也非常方便!)
n611x007 2013年

@ n611x007,echo Count is %argc%您将在其中插入自己的代码,该代码可以检查该计数是否正确,然后继续。
肯尼,2017年

7

试试这个:

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

6
这个答案与@nimrod一个有什么不同吗?...
蓝蓝的

1
在nimrodm的@FerdinandBeyer中查看评论。不会downvote,因为您有21个代表8)
n611x007

6

如果参数个数应该是一个精确的数(小于或等于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

2

避免以大小或可读性为代价使用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

编辑:这里使用的“技巧”涉及:

  1. 使用包含每个循环迭代中的百分比字符(%%)和计数器变量的字符串构造一个表示当前评估的命令行参数变量(即“%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测试作为返回变量()赋给子程序的变量是否未定义,如果不存在当前评估的命令行参数,则会发生这种情况。最初,这是将方括号中的返回变量的值与空方括号进行比较(这是我知道的测试程序或子程序参数的唯一方法,该程序或子程序参数可能包含引号,并且是试错阶段遗留下来的东西),但是从那时起就固定在现在的状态。


1
尽管此代码可以回答问题,但提供有关如何和/或为什么解决问题的其他上下文将提高​​答案的长期价值。
thewaywere是

@thewaywewere谢谢您,我一直忘记对于许多人(可能是大多数人),最好使用文本描述而不是“不言自明”的代码。
fen-fire

@ fen-fire,除了代码不是自我解释。
罗杜维克

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。您可以在任何函数中按索引引用参数。


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
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.