windows 批量while循环

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/1788473/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-09 06:55:43  来源:igfitidea点击:

While loop in batch

windowsbatch-filefor-loopwhile-loop

提问by Hellnar

Here is what I want, inside the BACKUPDIR, I want to execute cscript /nologo c:\deletefile.vbs %BACKUPDIR%until number of files inside the folder is greater than 21(countfilesholds it). Here is my code:

这是我想要的,在里面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%
)

回答by schnaader

set /a countfiles-=%countfiles%

This will set countfiles to 0. I think you want to decrease it by 1, so use this instead:

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

set /a countfiles-=1

I'm not sure if the for loop will work, better try something like this:

我不确定 for 循环是否有效,最好尝试这样的操作:

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

回答by paxdiablo

A whileloop can be simulated in cmd.exewith:

一个while循环可以模拟在cmd.exe有:

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

For example, the following script:

例如,以下脚本:

    @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

outputs:

输出:

0
1
2
3
4
5

For your particular case, I would start with the following. Your initial description was a little confusing. I'm assuming you want to delete files in that directory until there's 20 or less:

对于您的特定情况,我将从以下内容开始。你最初的描述有点令人困惑。我假设您想删除该目录中的文件,直到有 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
    )

回答by luke

@echo off

set countfiles=10

:loop

set /a countfiles -= 1

echo hi

if %countfiles% GTR 0 goto loop

pause

on the first "set countfiles" the 10 you see is the amount it will loop the echo hi is the thing you want to loop

在第一个“设置计数文件”上,您看到的 10 是它循环的数量 echo hi 是您想要循环的内容

...i'm 5 years late

……我迟到了 5 年

回答by Ben Personick

I have a trick for doing this!

我有一个技巧可以做到这一点!

I came up with this method because while on the CLI, it's not possible to use the methods provided in the other answers here and it had always bugged me.

我想出了这个方法,因为在 CLI 上,不可能使用这里其他答案中提供的方法,而且它一直困扰着我。

I call this the "Do Until Break" or "Infinite" Loop:

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

Basic Example

基本示例

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 )

This is truly an infinite loop!

这真的是一个无限循环!

This is useful for monitoring something in a CMDwindow, and allows you to use CTRL+Cto break it when you're done.

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

Want to Have a counter?

想要柜台吗?

Either use SET /AOR You can modify the FOR /LLoop to do the counting and still be infinite (Note, BOTH of these methods have a 32bit integer overflow)

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

SET /AMethod:

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  )

Native FOR /LCounter:

本地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  )

Counting Sets of 4294967295 and Showing Current Value of L:

计算 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 )

However, what if:

但是,如果:

  • You're interested in reviewing the output of the monitor, and concerned that I will pass the 9999 line buffer limit before I check it after it has completed.
  • You'd like to take some additional actions once the Thing I am monitoring is finished.
  • 您有兴趣查看监视器的输出,并担心我会在完成后检查之前超过 9999 行缓冲区限制。
  • 一旦我正在监控的事物完成,您想采取一些额外的措施。

For this, I determined how to use a couple methods to break the FORLoop prematurely effectively turning it into a "DO WHILE" or "DO UNTIL" Loop, which is otherwise sorely lacking in CMD.

为此,我确定了如何使用几种方法FOR过早地打破循环,有效地将它变成“ DO WHILE”或“ DO UNTIL”循环,否则 CMD 非常缺乏这种循环。

NOTE: Most of the time a loop will continue to iterate past the condition you checked for, often this is a wanted behavior, but not in our case.

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

Turn the "infinite Loop" into a "DO WHILE" / "DO UNTIL" Loop

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

UPDATE: Due to wanting to use this code in CMD Scripts (and have them persist!) as well as CLI, and on thinking if there might be a "more Correct" method to achieve this I recommend using the New method!

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

New Method(Can be used inside CMD Scripts without exiting the script):

新方法(无需退出脚本即可在 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
)

At CLI:

在 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
)

Original Method(Will work on CLI just fine, but will kill a script.)

原始方法(可以在 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

Older Post Stuff

较旧的帖子

Through chance I had hit upon some ways to exit loops prematurely that did not close the CMD prompt when trying to do other things which gave me this Idea.

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

NOTE:

笔记:

While ECHO.>&3 >NULhad worked for me in some scenarios, I have played with this off and on over the years and found that DIR >&0 >NULwas much more consistent.

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

I am re-writing this answer from here forward to use that method instead as I recently found the old note to myself to use this method instead.

我正在重新编写此答案以改用该方法,因为我最近发现自己的旧笔记改用此方法。

Edited Post with better Method Follows:

用更好的方法编辑帖子如下:

DIR >&0 >NUL

The >NUL is optional, I just prefer not to have it output the error.

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

I prefer to match inLine when possible, as you can see in this sanitized example of a Command I use to monitor LUN Migrations on our VNX.

我更喜欢在可能的情况下匹配 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 )

Also, I have another method I found in that note to myself which I just re-tested to confirm works just as well at the CLI as the other method.

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

Apparently, when I first posted here I posted an older iteration I was playing with instead of the two newer ones which work better:

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

In this method, we use EXIT /Bto exit the For Loop, but we don't want to exit the CLI so we wrap it in a CMD session:

在该方法中,我们使用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)

Because the loop itself happens in the CMD session, we can use EXIT /B to exit the iteration of the loop without losing our CMD Session, and without waiting for the loop to complete, much the same as with the other method.

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

I would go so far as to say that this method is likely the "intended" method for the sort of scenario where you want to break a for loop at the CLI, as using CMD session is also the only way to get Delayed expansion working at the CLI for your loops, and the behavior and such behavior is clearly an intended workflow to leave a CMD session.

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

IE: Microsoft clearly made an intentional effort to have CMD Exit /B For loops behave this way, while the "Intended" way of doing this, as my other method, relies on having accidentally created just the right error to kick you out of the loop without letting the loop finish processing, which I only happenstantially discovered, and seems to only reliably work when using the DIR command which is fairly strange.

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

So that said, I think it's probably a better practice to use Method 2:

话虽如此,我认为使用方法 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)

Although I suspect Method 1 is going to be slightly faster:

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

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

And in either case, both should allow DO-While loops as you need for your purposes.

在任何一种情况下,两者都应该允许 DO-While 循环,因为您需要满足您的目的。

回答by jayaram

It was very useful for me i have used in the following way to add user in active directory:

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

:: 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