【问题标题】:How to increment for loop variable in batch script?如何在批处理脚本中增加循环变量?
【发布时间】:2016-07-02 13:42:29
【问题描述】:
::Compare with available valid arguments
FOR /L %%i IN (1,1,!avArgc!) DO (
    FOR /L %%j IN (1,1,!argc!) DO (
        IF !avArgv[%%i]!==!argv[%%j]! (
            echo Match: !avArgv[%%i]!

            ::Check the next option
            SET /A nextArg=%%j
            SET /A nextArg+=1
            FOR /L %%n IN (!nextArg!,1,!nextArg!) DO ( 
                IF !nextArg! LEQ !argc! ( 
                    echo next arg: !argv[%%n]!
                    call :CheckSubOption
                )
            ) 
        )
    )
)

在我上面的代码示例中 - 我如何获取像 %%j 这样的 for 循环变量并在像这样 %%j++ 这样的 for 循环内自增?我目前的解决方案(这很混乱,我不喜欢它)是创建一个新变量并将其设置为 %%j 的值,然后递增该变量并开始使用该变量,如下所示:

::Check the next option
SET /A nextArg=%%j
SET /A nextArg+=1

【问题讨论】:

  • %%j 使用 for 循环解析。这意味着,在循环内部它已经被解析,所以它是一个固定值,而不是你可以改变的变量。恐怕,你必须忍受那个乱七八糟的新变量。
  • SET /A nextArg=%%j,不需要/a。它不应该受到伤害,但应该避免。另外,我怀疑这是为了我们的缘故而放入的,但是对于::Check the next option,永远不要在代码块中放入:: 命令,只是rem。可能有一些方法可以让您通过使用引用变量调用外部标签来更改它,但老实说,它甚至比添加新变量更混乱。
  • 感谢斯蒂芬回答了我的问题。 @Arescet ::rem 是可互换的,因此可以在代码块中使用它们。代码可以正常工作,我的 :: 添加 cmets 的方式加上 :: 更容易发现。
  • @ShadyProgrammer no,rem 是实际命令,:: 是具有无效起始字符的标签。 robvanderwoude.com/comments.phpss64.com/nt/rem.htmlstackoverflow.com/questions/12407800/… 显示了 :: 的问题,尽管它更快,但将它放在代码块中可能非常不可预测。

标签: batch-file scripting


【解决方案1】:

观察您的代码和您的意图,您似乎希望在循环结构中跳过数字。你想要改变它的方式会破坏稳定。在大多数脚本语言(例如 matlab、bash 和批处理)中,for 循环中使用的变量充当循环内的参考框架。 当您告诉代码运行特定的 for 循环时,无论其参数是否更改,它都会运行该计算。 一个真实的例子是教授使用过时的数字来解决一个问题,直到第二天他才收到新数据。教授不能相应地改变他的答案,因为他还没有新的数据。

这并不意味着这个问题无法解决。事实上,有多种方法可以解决这个问题。第一个稍微复杂一点的是嵌套的 For 结构。

@echo off
set /p maxLength=[Hi times?]
set skip=0

FOR /L %%i IN (1,1,%maxLength%) DO (call :subroutine %%i)

echo alright im done.
pause 
GOTO :eof

rem the below code uses a for loop structure that only loops 1 time based on the passed argument from the overall for loop as so to make changes to how its run.

:subroutine
set /a next=%1+%skip%
 FOR /L %%r IN (%next%,1,%next%+1) DO (call :routine %%r)
 GOTO :eof

:routine
if %1==3 (set /a skip=1)
echo %skip%
echo %next%
echo %1
pause
GOTO :eof

运行程序时,如果maxlength变量大于3,变量next会跳过3。

  • 之所以如此,是因为嵌套的 for 循环只运行一次 整个 for 循环的每次迭代

。这让程序有时间重置它使用的数据,这要归功于call 命令,它用作更新变量的一种方式。然而,这非常低效,并且可以用更少的代码行来完成。

第二个示例使用 GOTO 和 if 语句。

@echo off
set jump=1
:heyman
set /A "x+=%jump%"
if %x%==4 (set /A "jump=2")
echo %x%
if %x% LSS 10 goto heyman
echo done!

这段代码基本上会回显每次递增的 x 值,直到它达到 10 的值。然而,当它达到 4 时,增量会增加 1,因此每次运行循环时都会将 x 值递增 2。从您想要什么,您希望能够更改 %%j 的值递增方式,这是无法做到的,因为 %%j 是 for 循环在其计算中的位置的声明。使用 for 循环和 goto 语句可以完成的工作没有区别,只是它们的处理方式不同。

虽然很遗憾我还没有正确的代码形式,但我知道我提供的代码示例可以用来实现您的特定愿望。

【讨论】:

  • 谢谢,看来我的最终解决方案会像在这里问这个问题之前看起来一样混乱。您已经用粗体文本标记的句子回答了我的问题,另外还给了我一个想法,让我尝试将 GOTO 和 IF 语句组合在一起而不是 for 循环。
  • 不客气。请记住,有时一组不同的代码可能更适合您的需求。强制命令执行并非专门为处理而构建的事情并不总是一个好主意。
  • 如果您希望在 for 循环期间修改变量并在外部及时更新,请记住 for 循环仅在本地运行。您需要在代码的开头运行 setlocal enabledelayedexpansion 以允许根据正在运行的函数更新变量。因此,如果您有一个运行 set n+=1 的 for 循环,您可以使用 !n! 在 for 循环期间调用新更新的变量。
  • 它不像 bash 脚本等其他脚本语言那样在语法上优雅,但它的简单性和与其他微软功能的集成使它成为一种有用的学习语言。如果您没有帐户,这些可以是模拟按键或 youtube 视频的播放列表。并且考虑到大多数人使用 Windows(证明它看到的病毒数量),批处理脚本在很大程度上是可移植的,并且可以修改为与任何其他语言一样好。
【解决方案2】:

这种情况的一般解决方案是不依赖循环/if 内的块,而是使用不受评估级别阻塞的子例程。

FOR /L %%i IN (1,1,!avArgc!) DO call :Loop1 %%i
goto :EOF

:Loop1
FOR /L %%j IN (1,1,!argc!) DO call :Loop2 %1 %%j
goto :EOF

:Loop2
IF !avArgv[%1]!==!argv[%2]! (
            echo Match: !avArgv[%1]!

            ::Check the next option
            SET /A nextArg=%2+1
            call :CheckOpt %nextArg%
)
goto :EOF

:CheckOpt
IF %1 LEQ %argc% ( 
    echo next arg: !argv[%1]!
    call :CheckSubOption
)

【讨论】:

  • 好建议,虽然我觉得它会让我的代码从杂乱无章变成另一种杂乱无章,但我会用它来整理我的整体代码结构。谢谢。
猜你喜欢
  • 2014-06-24
  • 2011-02-05
  • 2017-02-12
  • 2016-05-17
  • 2012-03-19
  • 1970-01-01
  • 1970-01-01
  • 2012-07-11
  • 2011-02-10
相关资源
最近更新 更多