【问题标题】:While loop in batchwhile 批量循环
【发布时间】:2010-12-19 19:07:00
【问题描述】:

这就是我想要的,在BACKUPDIR 内,我想执行cscript /nologo c:\deletefile.vbs %BACKUPDIR% 直到文件夹内的文件数大于21(countfiles 持有它)。 这是我的代码:

@echo off
SET BACKUPDIR=C:\test
for /f %%x in ('dir %BACKUPDIR% /b ^| find /v /c "::"') do set countfiles=%%x

for %countfiles% GTR 21 (
cscript /nologo c:\deletefile.vbs %BACKUPDIR%
set /a countfiles-=%countfiles%
)

【问题讨论】:

  • 那么你的问题是什么?这批是否有效还是您的问题是它已损坏?

标签: windows batch-file for-loop while-loop


【解决方案1】:
set /a countfiles-=%countfiles%

这会将 countfiles 设置为 0。我认为您想将其减少 1,因此请改用:

set /a countfiles-=1

我不确定 for 循环是否会起作用,最好试试这样的:

:loop
cscript /nologo c:\deletefile.vbs %BACKUPDIR%
set /a countfiles-=1
if %countfiles% GTR 21 goto loop

【讨论】:

    【解决方案2】:

    while 循环可以在 cmd.exe 中模拟:

    :still_more_files
        if %countfiles% leq 21 (
            rem change countfile here
            goto :still_more_files
        )
    

    例如以下脚本:

        @echo off
        setlocal enableextensions enabledelayedexpansion
        set /a "x = 0"
    
    :more_to_process
        if %x% leq 5 (
            echo %x%
            set /a "x = x + 1"
            goto :more_to_process
        )
    
        endlocal
    

    输出:

    0
    1
    2
    3
    4
    5
    

    对于您的特定情况,我将从以下内容开始。你最初的描述有点混乱。我假设您要删除该目录中的文件,直到有 20 个或更少:

        @echo off
        set backupdir=c:\test
    
    :more_files_to_process
        for /f %%x in ('dir %backupdir% /b ^| find /v /c "::"') do set num=%%x
        if %num% gtr 20 (
            cscript /nologo c:\deletefile.vbs %backupdir%
            goto :more_files_to_process
        )
    

    【讨论】:

    • exaclty 你在说什么,但是它进入一个无限循环的问题,似乎 counfiles 应该在循环内减少,例如 set /a "countfiles = countfiles-1" 但它似乎对我不起作用。
    • @Hellnar,countfiles 再次设置为实际值,因为计算它的 for 语句是 inside 循环。我这样做是因为不清楚您的 VBScript 文件删除了多少文件。
    • 如果您有无限循环,请将“@echo off”替换为“::@echo off”并重新运行脚本。这将在命令执行时输出命令,您将看到 countfiles 被设置为什么。
    • 当您将其命名为while 时,它可以工作,您将其命名为while1 有什么原因吗?
    • @Noumenon:只是因为我倾向于在代码中有多个 while 循环。实际上,您几乎可以随心所欲地称呼它。我做的是让它更详细地阐明意图。
    【解决方案3】:

    我有一个诀窍!

    我想出了这种方法,因为在 CLI 上,无法使用此处其他答案中提供的方法,而且它一直困扰着我。

    我称之为“直到中断”或“无限”循环:

    基本示例

    FOR /L %L IN (0,0,1) DO @(
     ECHO. Counter always 0, See "%L" = "0" - Waiting a split second&ping -n 1 127.0.0.1>NUL )
    
    

    这真是一个无限循环!

    这对于监视 CMD 窗口中的某些内容很有用,并允许您在完成后使用 CTRL+C 来破坏它。

    想要专柜吗?

    要么使用SET /A 要么你可以修改FOR /L 循环来进行计数并且仍然是无限的(注意,这两种方法都有32位整数溢出)

    SET /A方法:

    FOR /L %L IN (0,0,1) DO @(
     SET /A "#+=1"&ECHO. L Still equals 0, See "%L = 0"!  - Waiting a split second &ping -n 1 127.0.0.1>NUL  )
    
    

    原生FOR /L计数器:

    FOR /L %L IN (-2147483648,1,2147483648) DO @(
     ECHO.Current value of L: %L - Waiting a split second &ping -n 1 127.0.0.1>NUL  )
    

    计数 4294967295 的集合并显示 L 的当前值:

    FOR /L %L IN (1,1,2147483648) DO @(
     (
      IF %L EQU 0 SET /A "#+=1">NUL
     )&SET /A "#+=0"&ECHO. Sets of 4294967295 - Current value of L: %L - Waiting a split second &ping -n 1 127.0.0.1>NUL )
    

    但是,如果:

    • 您有兴趣查看监视器的输出,并担心我会在完成后检查之前通过 9999 行缓冲区限制。
    • 我正在监视的事物完成后,您希望采取一些额外的措施。

    为此,我确定了如何使用几种方法来提前打破FOR 循环,从而有效地将其转换为“DO WHILE”或“DO UNTIL”循环,否则 CMD 非常缺乏这种循环。

    注意:大多数情况下,循环将继续迭代超过您检查的条件,这通常是一种想要的行为,但在我们的例子中不是。

    将“无限循环”变成“DO WHILE”/“DO UNTIL”循环

    更新:由于想在 CMD 脚本(并让它们持续存在!)以及 CLI 中使用此代码,并且考虑是否可能有“更正确”的方法来实现这一点,我建议使用新方法!

    新方法(无需退出脚本即可在 CMD 脚本中使用):

    FOR /F %%A IN ('
      CMD /C "FOR /L %%L IN (0,1,2147483648) DO @( ECHO.%%L & IF /I %%L EQU 10 ( exit /b  ) )"
    ') DO @(
      ECHO %%~A
    )
    

    在 CLI:

    FOR /F %A IN ('
      CMD /C "FOR /L %L IN (0,1,2147483648) DO @( ECHO.%L & IF /I %L EQU 10 ( exit /b  ) )"
    ') DO @(
      ECHO %~A
    )
    

    原始方法(可以在 CLI 上正常工作,但会杀死脚本。)

    FOR /L %L IN (0,1,2147483648) DO @(
      ECHO.Current value of L: %L - Waiting a split second &ping -n 1 127.0.0.1>NUL&(
        IF /I %L EQU 10 (
          ECHO.Breaking the Loop! Because We have matched the condition!&DIR >&0
        )
      )
    ) 2>NUL
    

    较早的帖子

    我偶然发现了一些过早退出循环的方法,在尝试做其他事情时没有关闭 CMD 提示符,这给了我这个想法。

    注意:

    虽然ECHO.>&3 >NUL 在某些情况下对我有用,但多年来我断断续续地使用它,发现DIR >&0 >NUL 更加一致。

    我正在从这里开始重写这个答案以使用该方法,因为我最近发现自己的旧笔记改为使用此方法。

    使用更好的方法编辑帖子:

    DIR >&0 >NUL
    

    >NUL 是可选的,我只是不想让它输出错误。

    我更喜欢在可能的情况下匹配 inLine,正如您在这个我用来监控 VNX 上的 LUN 迁移的命令的净化示例中看到的那样。

    for /l %L IN (0,0,1) DO @(
       ECHO.& ECHO.===========================================& (
         [VNX CMD] | FINDSTR /R /C:"Source LU Name" /C:"State:" /C:"Time " || DIR >&0 >NUL
       ) & Ping -n 10 1.1.1.1 -w 1000>NUL )
    

    另外,我在给自己的笔记中发现了另一种方法,我刚刚重新测试了它,以确认在 CLI 中的效果与其他方法一样好。

    显然,当我第一次在这里发帖时,我发布了一个我正在玩的旧版本,而不是两个更好用的新版本:

    在此方法中,我们使用EXIT /B 退出 For 循环,但我们不想退出 CLI,因此我们将其包装在 CMD 会话中:

    FOR /F %A IN ('CMD /C "FOR /L %L IN (0,1,10000000) DO @( ECHO.%L & IF /I %L EQU 10 ( exit /b  ) )" ') DO @(ECHO %~A)
    

    因为循环本身发生在 CMD 会话中,我们可以使用 EXIT /B 退出循环的迭代,而不会丢失我们的 CMD 会话,并且无需等待循环完成,这与其他方法非常相似。

    我什至会说,这种方法可能是您想要在 CLI 上中断 for 循环的场景的“预期”方法,因为使用 CMD 会话也是获得延迟的唯一方法在 CLI 上为您的循环工作的扩展,并且行为和此类行为显然是离开 CMD 会话的预期工作流。

    IE:Microsoft 显然有意让 CMD Exit /B For 循环以这种方式运行,而作为我的另一种方法,这样做的“预期”方式依赖于不小心创建了正确的错误来踢你在不让循环完成处理的情况下跳出循环,这是我偶然发现的,而且似乎只有在使用相当奇怪的 DIR 命令时才能可靠地工作。

    也就是说,我认为使用方法 2 可能是一个更好的做法:

    FOR /F %A IN ('CMD /C "FOR /L %L IN (0,1,10000000) DO @( ECHO.%L & IF /I %L EQU 10 ( exit /b  ) )" ') DO @(ECHO %~A)
    

    虽然我怀疑方法 1 会稍微快一些:

    FOR /L %L IN (0,1,10000000) DO @( ECHO.%L & IF /I %L EQU 10 ( DIR >&) >NUL ) )
    

    在任何一种情况下,两者都应根据您的目的允许 DO-While 循环。

    【讨论】:

    • 像 For /L %L in (0,1, BigNumber) 这样的循环或像 For /L %L in (0,0,1) 这样的无限循环非常低效。
    • @prampe A) For /L %_ IN (0,1,2147483648) DO [something] AND For /L %_ IN (0) DO [something] (或 For /L %_ IN (0,0,1) DO [something] )都是无限循环。 (末尾带有大量数字的较旧条目是复制粘贴工件。)也就是说,wirhout 甚至会与您讨论“哪种循环方法是最好的”——这是唯一可以直接和原生地在命令行界面。此外,等待单独进程完成然后退出循环的无限循环将需要超时,以免不必要地消耗 CPU 周期。
    【解决方案4】:
    @echo off
    
    set countfiles=10
    
    :loop
    
    set /a countfiles -= 1
    
    echo hi
    
    if %countfiles% GTR 0 goto loop
    
    pause
    

    在第一个“set countfiles”上,您看到的 10 是它将循环的数量 echo hi 是你想要循环的东西

    ...我晚了 5 年

    【讨论】:

      【解决方案5】:

      这对我来说非常有用,我用以下方式在活动目录中添加用户:

      :: This file is used to automatically add list of user to activedirectory
      :: First ask for username,pwd,dc details and run in loop
      :: dsadd user cn=jai,cn=users,dc=mandrac,dc=com -pwd `1q`1q`1q`1q
      
      @echo off
      setlocal enableextensions enabledelayedexpansion
      set /a "x = 1"
      set /p lent="Enter how many Users you want to create : "
      set /p Uname="Enter the user name which will be rotated with number ex:ram then ram1 ..etc : "
      set /p DcName="Enter the DC name ex:mandrac : "
      set /p Paswd="Enter the password you want to give to all the users : "
      
      cls
      
      :while1
      
      if %x% leq %lent% (
      
          dsadd user cn=%Uname%%x%,cn=users,dc=%DcName%,dc=com -pwd %Paswd%
          echo User %Uname%%x% with DC %DcName% is created
          set /a "x = x + 1"
          goto :while1
      )
      
      endlocal
      

      【讨论】:

        猜你喜欢
        • 2017-04-16
        • 2017-06-15
        • 2020-05-15
        • 1970-01-01
        • 1970-01-01
        • 2016-04-24
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多