Windows批处理文件数组提取计数器没有递增+ =

时间:2013-01-05 06:10:00

标签: windows shell batch-file

我正在将shell脚本翻译成Windows批处理。我需要做的是从命令行参数中获取除1,2和最后的所有内容。加入他们并发送到另一个程序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]

e.g。如果我写batch x 2 a b p,它应该将a b传递给另一个程序

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

4 个答案:

答案 0 :(得分:1)

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

考虑到问题 Parse命令行,将第二个参数作为参数计数连接到变量,这是我的看法:

@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%

请注意我没有检查是否有'挂'参数(最后一个,没有被连接)但是添加该检查应该是微不足道的。我故意把它留下来让代码更灵活。

答案 1 :(得分:1)

我的问题有两个答案:

1-第一个问题是在IF %i% ...命令中i变量的值不变(尽管set /a i+=1命令正确地增加变量)和解决方法它是通过在开头包含setlocal EnableDelayedExpansion命令并以这种方式用百分比符号括起来: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%

安东尼奥

答案 2 :(得分:0)

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

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

@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行上做什么作为括号并不意味着批量生产。

答案 3 :(得分:0)

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

这将根据您的需要[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%