web-dev-qa-db-fra.com

Quitter une boucle FOR dans un fichier de commandes?

Pourquoi ce fichier de commandes ne sort-il jamais de la boucle?

For /L %%f In (1,1,1000000) Do @If Not Exist %%f Goto :EOF

Le Goto :EOF ne devrait-il pas sortir de la boucle?

Modifier:

Je suppose que j'aurais dû demander plus explicitement ... comment puis-je sortir de la boucle?

19
Mehrdad

Vous pouvez simplement utiliser echo on et vous verrez que goto :eof ou même exit /b ne fonctionne pas comme prévu. 

Le code à l'intérieur de la boucle n'est plus exécuté, mais la boucle est développée pour tous les nombres jusqu'à la fin.
C'est pourquoi c'est si lent.

La seule façon de sortir d'une boucle FOR/L semble être la variante de exit comme l'exemple de Wimmel, mais ce n'est ni très rapide ni utile pour accéder aux résultats de la boucle.

Cela montre 10 extensions, mais aucune d'entre elles ne sera exécutée

echo on
for /l %%n in (1,1,10) do (
  goto :eof
  echo %%n
)
6
jeb

Basé sur la deuxième édition de Tim et cette page vous pouvez le faire:

@echo off
if "%1"=="loop" (
  for /l %%f in (1,1,1000000) do (
    echo %%f
    if exist %%f exit
  )
  goto :eof
)
cmd /v:on /q /d /c "%0 loop"
echo done

Cette page suggère un moyen d’utiliser un goto dans une boucle, cela semble fonctionner, mais cela prend du temps dans une grande boucle. Donc, en interne, il termine la boucle avant l'exécution de la goto.

6
wimh

Donc, je réalise que c'est un peu vieux, mais après beaucoup de recherches sur Google, je ne pouvais pas trouver de réponse qui me satisfasse, alors j'ai proposé ma propre solution pour casser une boucle FOR qui arrête immédiatement l'itération, et j'ai pensé partager il.

La boucle doit figurer dans un fichier séparé et exploite un bogue dans la gestion des erreurs CMD pour bloquer immédiatement le traitement par lots du fichier de boucle lors de la redirection du STDOUT de DIR vers STDIN.

MainFile.cmd

ECHO Simple test demonstrating loop breaking.
ECHO.
CMD /C %~dp0\LOOP.cmd
ECHO.
ECHO After LOOP
PAUSE

LOOP.cmd

FOR /L %%A IN (1,1,10) DO (
    ECHO %%A
    IF %%A EQU 3 DIR >&0 2>NUL  )
)

Lorsqu'il est exécuté, cela produit la sortie suivante. Vous remarquerez que l'itération et l'exécution de la boucle s'arrêtent lorsque% A = 3.

:>MainFile.cmd

:>ECHO Simple test demonstrating loop breaking.
Simple test demonstrating loop breaking.

:>ECHO.


:>CMD /C Z:\LOOP.cmd

:>FOR /L %A IN (1 1 10) DO (
ECHO %A
 IF %A EQU 3 DIR         1>&0 2>NUL
)

:>(
ECHO 1
 IF 1 EQU 3 DIR          1>&0 2>NUL
)
1

:>(
ECHO 2
 IF 2 EQU 3 DIR          1>&0 2>NUL
)
2

:>(
ECHO 3
 IF 3 EQU 3 DIR          1>&0 2>NUL
)
3

:>ECHO.


:>ECHO After LOOP
After LOOP

:>PAUSE
Press any key to continue . . .

Si vous devez conserver une seule variable de la boucle, indiquez à la boucle ECHO le résultat de la variable et utilisez une boucle FOR/F dans MainFile.cmd pour analyser la sortie du fichier LOOP.cmd.

Exemple (utilisant le même fichier LOOP.cmd que ci-dessus):

MainFile.cmd

@ECHO OFF
ECHO.
ECHO Simple test demonstrating loop breaking.
ECHO.
FOR /F "delims=" %%L IN ('CMD /C %~dp0\LOOP.cmd') DO SET VARIABLE=%%L
ECHO After LOOP
ECHO.
ECHO %VARIABLE%
ECHO.
PAUSE

Sortie:

:>MainFile.cmd

Simple test demonstrating loop breaking.

After LOOP

3

Press any key to continue . . .

Si vous devez conserver plusieurs variables, vous devrez les rediriger vers des fichiers temporaires, comme indiqué ci-dessous.

MainFile.cmd

@ECHO OFF
ECHO.
ECHO Simple test demonstrating loop breaking.
ECHO.
CMD /C %~dp0\LOOP.cmd
ECHO After LOOP
ECHO.
SET /P VARIABLE1=<%TEMP%\1
SET /P VARIABLE2=<%TEMP%\2
ECHO %VARIABLE1%
ECHO %VARIABLE2%
ECHO.
PAUSE

LOOP.cmd

@ECHO OFF
FOR /L %%A IN (1,1,10) DO (
    IF %%A EQU 1 ECHO ONE >%TEMP%\1
    IF %%A EQU 2 ECHO TWO >%TEMP%\2
    IF %%A EQU 3 DIR >&0 2>NUL
)

Sortie:

:>MainFile.cmd

Simple test demonstrating loop breaking.

After LOOP

ONE
TWO

Press any key to continue . . .

J'espère que d'autres trouveront cela utile pour rompre des boucles dont la sortie prendrait trop de temps en raison d'une itération continue.

1
John Hofmann

Comme jeba noté , le reste de la boucle est ignoré mais évalué, ce qui rend la solution FOR trop lente à cette fin. Une alternative:

set F=1
:nextpart
if not exist "%F%" goto :EOF
echo %F%
set /a F=%F%+1
goto nextpart

Vous devrez peut-être utiliser expansion retardée et call lors de l’utilisation de cela dans les boucles.

1
Michel de Ruiter

En supposant que l'OP appelle un fichier de commandes avec cmd.exe, pour sortir correctement d'une boucle for, allez simplement à une étiquette;

Change ça:

For /L %%f In (1,1,1000000) Do If Not Exist %%f Goto :EOF

Pour ça:

For /L %%f In (1,1,1000000) Do If Not Exist %%f Goto:fileError
.. do something
.. then exit or do somethign else

:fileError
GOTO:EOF

Mieux encore, ajoutez des rapports d'erreur:

set filename=
For /L %%f In (1,1,1000000) Do(
    set filename=%%f
    If Not Exist %%f set tempGoto:fileError
)
.. do something
.. then exit or do somethign else

:fileError
echo file does not exist '%filename%'
GOTO:EOF

Je trouve que ce site est utile à propos des astuces et des fonctions de fichier de commandes cmd.exe/DOS moins connues: https://www.dostips.com/

0
The Coordinator