2013-03-12 63 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