0

我正在将一个 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给另一个程序

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

4

4 回答 4

1

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

1-第一个问题是在IF %i% ...命令中 i 变量的值不会改变(尽管set /a i+=1命令正确地增加变量),解决它的方法是setlocal EnableDelayedExpansion在开头包含命令并将 i 括在百分号中:(IF !i! ...如在以前的答案)。但是,您必须注意,批处理中的数组变量与同名的简单变量不同(它们都可以同时存在),因此数组元素必须始终使用下标编写,并且无法在批处理中处理整个数组一次操作。有关详细信息,请参阅此主题

在您的程序中,您必须将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-独立于上面解释的数组管理,这是我使用列表而不是数组来解决您的问题的方法:

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

安东尼奥

于 2013-01-05T18:05:29.007 回答
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%

请注意,我没有检查是否有“悬挂”参数(最后一个,没有被连接),但添加该检查应该很简单。我故意将其省略以使代码更灵活。

于 2013-01-05T09:58:44.223 回答
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%
于 2013-01-05T19:05:07.030 回答
0

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

要禁用它,您需要启用延迟扩展并将变量转义字符从%'s 更改为!'s 以在运行时进行替换。然后你会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因为括号在批处理中没有任何意义。

于 2013-01-05T07:45:50.820 回答