2013-03-12 18 views
5

我有这个循环可以为外部文件中的每一行重复。我想提示用户每次都有选择,但这不起作用。我认为问题在于GOTO命令以某种方式打破了循环。对此有何想法?FOR循环中的选择 - Windows批处理

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 for循环将停止循环。解决方法是用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 2013-03-12 13:03:05

+0

+1,但我也发布了一个替代答案。 – jimhark 2013-03-12 13:36:04

5

@ Metzger的回答是一个好的开始(我投了票),但是我发现了一些问题。最后,我更愿意将代码内联并避免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这些是很好的要点。 **':)'**尤其是,关于可能在UNINSTALL中设置的ERRORLEVEL。我想过提及传递'%% i'作为参数,但认为它不是必需的(按照7和8的原理工作)。 – 2013-03-12 13:47:13

+0

upvoted,谢谢 – Ozrix 2013-03-12 13:50:15

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