我正在将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总是
答案 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%