2013-03-12 5 views
5

J'ai cette boucle qui se répète pour chaque ligne dans un fichier externe. Je voudrais inviter l'utilisateur pour un choix dans chaque passe, bien que cela ne fonctionne pas. Je pense que le problème est avec la commande GOTO qui brise la boucle en quelque sorte. Des pensées à ce sujet?CHOICE dans la boucle FOR - Windows Batch

FOR /F %%i IN (%WORKDIR%\grunt-packages.ini) DO (
    CHOICE /C AN /M "Odinstalovat plugin" 
    IF %ERRORLEVEL%==1 GOTO UNINSTALL 
    IF %ERRORLEVEL%==2 GOTO SKIP 

    :UNINSTALL 
     ECHO Odstranuji %%i 
     CALL npm uninstall %%i 

    :SKIP 
     ECHO Preskakuji %%i 
) 

Répondre

8

Votre calcul est correct. goto dans les boucles pour arrêter la boucle. Le moyen de contourner cela est d'utiliser call à la place. Cependant, le premier problème avec votre script est le besoin d'expansion retardée pour la variable ERRORLEVEL. Chaque fois que vous développez des variables définies dans une portée parenthèses, utilisez l'expansion différée pour obtenir la dernière valeur.

SETLOCAL ENABLEEXTENSIONS ENABLEDELAYEDEXPANSION 
FOR /F %%i IN (%WORKDIR%\grunt-packages.ini) DO (
    CHOICE /C AN /M "Odinstalovat plugin" 
    IF !ERRORLEVEL!==1 CALL :UNINSTALL 
    IF !ERRORLEVEL!==2 CALL :SKIP 
) 
ENDLOCAL 
GOTO :EOF 

:UNINSTALL 
    ECHO Odstranuji %%i 
    CALL npm uninstall %%i 
    GOTO :EOF 

:SKIP 
    ECHO Preskakuji %%i 
    GOTO :EOF 
  1. gotone peut pas être utilisé dans lesfor boucles.
  2. Les variables définies entre parenthèses nécessitent un développement différé pour récupérer la nouvelle valeur. ! au lieu de %. Sinon, la valeur de la variable d'avant la portée parenthèses sera utilisée.
+0

brillante, merci! – Ozrix

+0

+1, mais j'ai aussi posté une réponse alternative. – jimhark

5

@ La réponse de Metzger était un bon début (j'ai voté pour), mais j'ai trouvé quelques problèmes. Au final, je préfère mettre le code en ligne et éviter le CALLs. Voici mon code de test pour montrer comment il est fait:

@echo off 
SETLOCAL ENABLEEXTENSIONS ENABLEDELAYEDEXPANSION 
FOR %%i IN (A B C D) DO (
    CHOICE /C AN /M "Uninstall plugin %%i" 
    IF !ERRORLEVEL!==1 (
     ECHO Uninstall %%i 
    ) ELSE IF !ERRORLEVEL!==2 (
     ECHO Skip %%i 
    ) 
) 

j'ai testé @ réponse de Metzger sur Windows XP et déniché les questions suivantes:

  • Subroutines manquantes GOTO :EOF (déjà fixé)
  • Sous Windows XP , dans les sous-routines %%i est unset
  • (bug potentiel) Si désinstaller ensembles ERRORLEVEL, SKIP peut être appelé

Ce code de test corrige les problèmes:

@echo off 
SETLOCAL ENABLEEXTENSIONS ENABLEDELAYEDEXPANSION 
FOR %%i IN (A B C D) DO (
    CHOICE /C AN /M "Uninstall plugin %%i" 
    SET OERRORLEVEL=!ERRORLEVEL! 
    IF !ERRORLEVEL!==1 CALL :UNINSTALL %%i 
    IF !OERRORLEVEL!==2 CALL :SKIP %%i 
) 
ENDLOCAL 
GOTO :EOF 

:UNINSTALL 
    ECHO Uninstall %1 
    GOTO :EOF 

:SKIP 
    ECHO Skip %1 
    GOTO :EOF 
+0

+1 Ce sont de bons points à noter. ** ':)' ** Surtout, ERRORLEVEL peut être défini dans UNINSTALL. J'ai pensé mentionner le passage de '%% i' comme paramètre, mais je me suis dit que ce n'était pas nécessaire (ça marche sur 7 et 8 comme ça). –

+0

mis à jour, merci – Ozrix

1

Cette structure évite l'utilisation de DELAYEDEXPANSION

@ECHO OFF 
SETLOCAL 
FOR %%i IN (A B C D) DO (
SET destcall=BADCHOICE 
choice /c QJ /M "%%i - choose Q or J" 
IF ERRORLEVEL 1 SET destcall=CHOSEQ 
IF ERRORLEVEL 2 SET destcall=CHOSEJ 
CALL CALL :%%destcall%% 
) 
GOTO :eof 

:badchoice 
ECHO bad choice 
GOTO :eof 

:choseq 
ECHO You chose Q 
GOTO :eof 

:chosej 
ECHO You chose J 
GOTO :eof 
Questions connexes