Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

CHOICE in FOR loop - Windows Batch

Tags:

batch-file

I have this loop that repeats itself for every line in an external file. I would like to prompt the user for a choice in every pass, though this doesn't work. I reckon the problem is with the GOTO command breaking the loop somehow. Any thoughts on this?

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
)
like image 888
Ozrix Avatar asked Mar 12 '13 12:03

Ozrix


2 Answers

Your reckoning is correct. goto within for loops will stop the loop. The way around this is to use call instead. However, the first issue with your script is the need of delayed expansion for the ERRORLEVEL variable. Whenever expanding variables that are set within a parentheses scope, use delayed expansion to get the latest value.

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 cannot be used within for loops.
  2. Variables set within parentheses need delayed expansion to retrieve the new value. ! instead of %. Otherwise, the value of the variable from before the parentheses scope will be used.
like image 105
David Ruhmann Avatar answered Nov 04 '22 11:11

David Ruhmann


@Metzger's answer was a good start (I up-voted it), but I found some problems with it. In the end, I prefer to put the code inline and avoid the CALLs. Here's my test code to show how it's done:

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

I tested @Metzger's answer on Windows XP and found the following issues:

  • Subroutines missing GOTO :EOF (already fixed)
  • On Windows XP, in the subroutines %%i is unset
  • (Potential bug) If uninstall sets ERRORLEVEL, SKIP might be called

This test code fixes the problems:

@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
like image 40
jimhark Avatar answered Nov 04 '22 10:11

jimhark