【问题标题】:windows batch file array extraction counter not being incremented by +=Windows 批处理文件数组提取计数器未按 += 递增
【发布时间】:2013-01-05 06:10:00
【问题描述】:

我正在将一个 shell 脚本翻译成 windows 批处理。我需要做的是从命令行参数中获取除 1,2 和 last 之外的所有内容。加入他们并作为 argv 发送到另一个程序。

@echo off

SET subject=%1
set count=%2
set candidates=""
set /a i=0
set /a c=0
FOR %%A IN (%*) DO (
  ECHO %%A
  set /a i+=1
  IF %i% geq 2 (
    set /a c+=1;
    set candidates[!c!]=%%A
  )
)
SET /a count_actual=(%i%-3)
SET /a count_expected=%count%
echo %count_expected%
echo %count_actual%
echo %subject%
echo %candidates%

我希望候选数组为argv[3..n-1]

例如如果我写 batch x 2 a b p 它应该将 a b 传递给另一个程序

问题是循环计数器没有被 += 运算符递增。如果我在FOR 内写echo %1%,我总是看到0

【问题讨论】:

  • 要查看在循环内修改的变量的值,您必须启用延迟扩展。将其放在脚本的开头setlocal EnableDelayedExpansion。有关帮助和定义,请参阅 setlocal /?

标签: windows shell batch-file


【解决方案1】:

您不应使用for %%A in (%*),因为它将%* 视为文件名集。这可能会导致问题,特别是如果您可以在参数中传递*?(cmd 中的通配符匹配字符) - 因为它们将扩展到所有满足模式的文件。其次,batch 确实对数组一无所知——a[1] 和 a[2] 只是人类的简写符号——它们是两个不同的变量。

鉴于问题解析命令行,将第二个参数作为参数计数以连接成一个变量,这是我的看法:

@echo off
setlocal

set subject=%1

shift
set exp_count=%1

if not defined exp_count (
  echo Count not specified
  exit /b 1
)
set /a "verify=%exp_count%"
if %verify% leq 0 (
  echo Count not valid /not a positive integer/
  exit /b 2
)

set real_count=0
:loop
    shift
    if "%~1"=="" goto end_params
    set /a real_count+=1
    if %real_count% leq %exp_count% set "candidates=%candidates%%~1"
    goto loop
  )

:end_params
if %real_count% lss %exp_count% (
  echo Less parameters passed than specified!
  exit /b 3
)

echo %subject%
echo %candidates%

请注意,我没有检查是否存在“悬挂”参数(最后一个,未连接),但添加该检查应该是微不足道的。我故意将其省略以使代码更灵活。

【讨论】:

    【解决方案2】:

    对于你的问题,我有两个答案:

    1- 第一个问题是在IF %i% ... 命令中 i 变量的值不会改变(尽管set /a i+=1 命令 正确地增加变量),解决它的方法是包含setlocal EnableDelayedExpansion 命令在开头并以这种方式将 i 括在百分号中:IF !i! ... (如前面的答案中所述)。但是需要注意的是,Batch 中的数组变量不同于同名的简单变量(它们可以同时存在),所以数组元素必须总是用下标编写,没有办法在一次操作中处理整个数组。详情请见this topic

    在您的程序中,您必须将 candidates 数组的元素转换为一个简单的变量,在下面的示例中具有相同的名称(只是为了说明我的观点):

    @echo off
    setlocal EnableDelayedExpansion
    SET subject=%1
    set count=%2
    set candidates=""
    set /a i=0
    set /a c=0
    FOR %%A IN (%*) DO (
      ECHO %%A
      set /a i+=1
      IF !i! geq 2 (
        set /a c+=1
        set candidates[!c!]=%%A
      )
    )
    SET /a count_actual=(%i%-3)
    SET /a count_expected=%count%
    echo %count_expected%
    echo %count_actual%
    echo %subject%
    REM Transfer "candidates" array elements into "candidates" simple variable:
    set candidates=
    FOR /L %%i IN (1,1,%c%) do (
       set candidates=!candidates! !candidates[%%i]!
    )
    REM Show "candidates" simple variable:
    echo %candidates%
    

    请注意,在批处理文件中,您可以在大多数命令中插入逗号、分号和等号作为分隔符,而不是空格。但是SET /A命令在这方面有其他规定,所以分号必须省略。

    2- 独立于上面解释的数组管理,这是我使用 list 而不是数组来解决您的问题的方法:

    @echo off
    SET subject=%1
    shift
    set count=%1
    set candidates=
    set lastArg=
    set i=0
    :nextArg
       shift
       if "%1" equ "" goto endArgv
       set /a i+=1
       set candidates=!candidates! !lastArg!
       set lastArg=%1
       goto nextArg
    :endArgv
    SET /a count_actual=i-3, count_expected=count
    echo %count_expected%
    echo %count_actual%
    echo %subject%
    echo %candidates%
    

    安东尼奥

    【讨论】:

      【解决方案3】:

      是的,您的代码不会增加 i。批量变量替换发生在解析块时,而不是执行时。整个for 块被解析一次,所以%i% 在执行for 块之前被替换为零。

      要禁用它,您需要 enable delayed expansion 并将变量转义字符从 % 更改为 ! 以在运行时进行替换。然后你会看到ifor 循环中递增。

      @echo off
      Setlocal EnableDelayedExpansion
      
      SET subject=%1
      set count=%2
      set candidates=""
      set /a i=0
      set /a c=0
      FOR %%A IN (%*) DO (
        ECHO %%A
        set /a i+=1
        IF !i! geq 2 (
          set /a c+=1
          set candidates[!c!]=%%A
        )
      )
      SET /a count_actual=(%i%-3)
      SET /a count_expected=%count%
      echo %count_expected%
      echo %count_actual%
      echo %subject%
      echo %candidates%
      

      您还需要去掉set /a c+=1; 行末尾的;,我不确定您在set candidates[!c!]=%%A 行上要做什么,因为括号在批处理。

      【讨论】:

      • 我正在尝试将 %%A 附加到 candidates 数组。其实我想切片argv[3..n-1]
      • 但它没有向该数组附加任何内容。而是根本不将其视为数组
      • @DiproSen - 批处理没有数组 - 你能做的最好的就是追加:set candidates=!candidates! %%A
      • @shf301:“批处理没有数组”是什么意思?批处理文件可以以与其他编程语言等效的方式管理数组!看我的回答...
      【解决方案4】:

      虽然已经列出了很多答案,但我决定再添加一个。我的方法是根据您的特定需求使答案尽可能简单。如果您有任何问题,请随时提出。

      这将根据需要创建数组 [3,...,n-1],而无需延迟扩展或花哨的逻辑。

      @echo off
      
      :: Get the First Two Parameters    
      set "subject=%1"
      shift
      set "count=%1"
      shift
      
      :: Loop through the rest
      set "index=0"
      :NextParam
      set "param=%1"
      shift
      set "next=%1"
      :: Skip the last parameter
      if not defined next goto EndParam
      set "candidates[%index%]=%param%"
      set /a "index+=1"
      goto NextParam
      :EndParam
      
      set "count_actual=%index%"
      set "count_expected=%count%"
      
      :: Show the Results
      echo %count_actual%
      echo %count_expected%
      echo %subject%
      set candidates
      

      这是另一种选择,候选存储在空格分隔的字符串中,而不是单独的变量中。将%candidates% %param% 之间的空格替换为您想要的任何分隔符。

      @echo off
      
      :: Get the First Two Parameters  
      set "subject=%1"
      shift
      set "count=%1"
      shift
      
      :: Loop through the rest
      set "index=0"
      :NextParam
      set "param=%1"
      shift
      set "next=%1"
      :: Skip the last parameter
      if not defined next goto EndParam
      set "candidates=%candidates% %param%"
      set /a "index+=1"
      goto NextParam
      :EndParam
      
      set "count_actual=%index%"
      set "count_expected=%count%"
      
      :: Show Results
      echo %count_actual%
      echo %count_expected%
      echo %subject%
      echo %candidates%
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2017-08-10
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-08-09
        相关资源
        最近更新 更多