【问题标题】:Batch files - number of command line arguments批处理文件 - 命令行参数的数量
【发布时间】:2010-11-20 11:41:47
【问题描述】:

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

例如。如果你有:

myapp foo bar

在外壳中:

  • $# -> 2
  • $* -> 富吧
  • $0 -> 我的应用程序
  • $1 -> 富
  • $2 -> 条

批量

  • ?? -> 2
  • %* -> 富吧
  • %0 -> 我的应用程序
  • %1 -> 富翁
  • %2 -> 条形

所以我环顾四周,要么我看错了地方,要么我失明了,但我似乎无法找到一种方法来计算传入的命令行参数的数量。

有没有类似shell的"$#"的批处理文件命令?

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

【问题讨论】:

  • 你的字符串是2 myapp foo bar ?
  • 建议:不要将 sh 转换为 BAT。相反,下载 cygwin 并使用它。即您的 sh 脚本将在 Windows 机器上运行。而且您不必将每个 sh 都翻译成 BAT!

标签: shell batch-file scripting


【解决方案1】:

谷歌搜索一下,你会得到来自wikibooks的以下结果:

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

echo %argC%

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

【讨论】:

  • 请注意,for 的这种变体仅适用于看起来像文件名的参数,而不适用于诸如 -? 之类的选项字符串。使用引号 (for %%i in ("%*") ...) 适用于 -? 之类的参数,但由于嵌套引号,引用参数再次失败。唯一可靠的方法似乎涉及shift...
  • MyBatchFile "*.*" "Abc" 报告 argC == 9。 -- 否决。
  • 已将其作为函数测试了 2500 个参数,并使用它来定义相同大小的数组。不要问我到底为什么。主要是学习批处理的能力。
【解决方案2】:

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

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

等等

如果你有超过 9 个参数,那么你就会被这种方法搞砸了。有多种创建计数器的技巧,您可以找到 here,但请注意,这些技巧不适合胆小的人。

【讨论】:

  • 您仍然可以使用shift 来计算超过 9 个...并且没有 10 行相同外观的代码。
【解决方案3】:

下面的函数:getargc 可能就是你要找的。​​p>

@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 echo Count is %argc% 你可以插入你自己的代码来检查计数是否正确,然后继续。
【解决方案4】:

试试这个:

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

【讨论】:

  • 这个答案和@nimrod one有什么不同吗?...
  • 查看@FerdinandBeyer 在 nimrodm 中的评论。不会因为你有 21 个代表而投票反对 8)
【解决方案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

【讨论】:

    【解决方案6】:

    以大小和可读性为代价避免使用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. 使用包含百分比字符 (%%) 和计数器变量的字符串构造表示当前计算的命令行参数变量(即“%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) 的子程序的变量被测试为未定义,如果当前评估的命令行参数不存在,则会发生这种情况。最初,这是将返回变量的值括在方括号中与空方括号进行比较(这是我所知道的测试可能包含引号的程序或子程序参数的唯一方法,并且是试错阶段被忽视的遗留物)但是从此固定到现在的样子。

    【讨论】:

    • 虽然此代码可能会回答问题,但提供有关它如何和/或为什么解决问题的额外上下文将提高​​答案的长期价值。
    • @thewaywewere 谢谢你,我一直忘记,对于很多人(可能是大多数人)来说,最好有文本描述而不是“不言自明”的代码。
    • @fen-fire 只是代码不是自我解释的。
    【解决方案7】:

    最后一个答案是两年前的现在,但我需要一个版本超过九个命令行参数。可能是另一个也有...

    @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 样式的变量。所有其他东西只是探测结果并显示转换为本地参数。您可以在任何函数中按索引引用参数。

    【讨论】:

      【解决方案8】:

      一个健壮的解决方案是将计数委托给使用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
      

      【讨论】:

        猜你喜欢
        • 2023-03-11
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2013-11-27
        • 1970-01-01
        • 1970-01-01
        • 2019-08-30
        相关资源
        最近更新 更多