2013-03-12 4 views
5

У меня есть этот цикл, который повторяется для каждой строки во внешнем файле. Я хотел бы предложить пользователю выбрать в каждом проходе, хотя это не работает. Я считаю, что проблема заключается в том, что команда GOTO нарушает цикл как-то. Любые мысли по этому поводу?CHOICE in FOR loop - 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 
) 

ответ

8

Ваше расстройство верное. goto внутри петель остановит цикл. Таким образом, вместо этого следует использовать call. Однако первая проблема с вашим скриптом - необходимость отсроченного расширения для переменной ERRORLEVEL. Всякий раз, когда расширяются переменные, заданные в круглых скобках, используйте задержанное расширение, чтобы получить последнее значение.

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. gotoне может использоваться в пределах for петель.
  2. Переменные, установленные в круглых скобках, требуют отсроченного расширения для получения нового значения. ! вместо %. В противном случае будет использоваться значение переменной до области круглых скобок.
+0

блестящей, спасибо! – Ozrix

+0

+1, но я также разместил альтернативный ответ. – jimhark

5

@ Ответ Мецгера был хорошим началом (я проголосовал за это), но я нашел некоторые проблемы с ним. В конце концов, я предпочитаю вставлять код в строку и избегать CALLs. Вот мой тестовый код, чтобы показать, как это делается:

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

Я протестированный @ ответ Мецгеровского на Windows XP и нашел следующие вопросы:

  • Подпрограммы отсутствующей GOTO :EOF (уже фиксированный)
  • В Windows XP , в подпрограммах %%i снята с охраны
  • (Потенциальная ошибка) Если удалить наборы ERRORLEVEL, SKIP можно назвать

Этот тест код исправляет проблемы:

@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 Это хорошие моменты для заметок. ** ':)' ** Тем более, что ERRORLEVEL, возможно, установлен в UNINSTALL. Я подумал о том, чтобы указать параметр «%% i» в качестве параметра, но считал, что он не нужен (работает на 7 и 8 как есть). –

+0

upvoted, спасибо – Ozrix

1

Эта структура позволяет избежать использования 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