2014-06-11 79 views
1

我有一個批處理文件,它接受操作模式作爲參數,並根據它以特定順序運行幾個命令,不知有沒有其他方法來處理這個批處理文件還有很多IF語句?帶分支的批處理文件 - if語句的替代

這不是一個真正的代碼 - 只是表示該流

Get MODE as Parameter 
If MODE=TYPE1 or MODE=TYPE2 then 
    Run Command A 
endif 

If MODE=TYPE1 or MODE=TYPE3 then 
    Run Command B 
endif 

If MODE=TYPE3 then 
    Run Command C 
endif 
+0

可能[在Windows批處理文件中相當於switch語句]的副本(http://stackoverflow.com/questions/18423443/switch-statement-equivalent-in-windows-batch-file) –

+0

你在說幾個案子?按照您的方式測試的批處理命令對於每種情況都是單行的。您也可以在一個文本文件中包含案例和可執行文件,並從批處理命令中檢查這些案例和可執行文件,但實際的細節將決定它的完成方式。 – foxidrive

回答

2
@echo off 
    setlocal enableextensions 

    set "MODE=%~1" 
    set "WHENMODE=call :testCase "%MODE%" " 

    %WHENMODE% TYPE1 TYPE2 && (
     echo Run command A 
    ) 

    %WHENMODE% TYPE1 TYPE3 && (
     echo Run command B 
    ) 

    %WHENMODE% TYPE3 && (
     echo Run command C 
    ) 

    endlocal 
    exit /b 

:testCase value test1 test2 ... testn 
    if "%~2"=="" exit /b 1 
    if "%~1"=="%~2" exit /b 0 
    shift /2 & goto %0 

%WHENMODE%定義僅美感。沒有裝飾的相同代碼

@echo off 
    setlocal enableextensions 

    set "MODE=%~1" 

    call :testCase "%MODE%" TYPE1 TYPE2 && echo Run command A 
    call :testCase "%MODE%" TYPE1 TYPE3 && echo Run command B 
    call :testCase "%MODE%" TYPE3  && echo Run command C 

    endlocal 
    exit /b 

:testCase value test1 test2 ... testn 
    if "%~2"=="" exit /b 1 
    if "%~1"=="%~2" exit /b 0 
    shift /2 & goto %0 
+0

+1,非常優雅地使用一個簡單的宏 – dbenham

2

首先,我認爲謹慎地展示如何用IF語句來實現。批量IF不支持OR邏輯。下面模仿OR:

@echo off 
setlocal enableDelayedExpansion 
set "mode=%~1" 

set "aModes= TYPE1 TYPE2 " 
set "bModes= TYPE1 TYPE3 " 
set "cModes= TYPE3 " 

if "!aModes:%mode%=!" neq "!aModes!" echo command A 
if "!bModes:%mode%=!" neq "!bModes!" echo command B 
if "!cModes:%mode%=!" neq "!cModes!" echo command C 

現在可能的替代品,如果我能想到的

1)一個半現實的事情就是使用模式作爲標籤,但我不喜歡它。不必要的使用CALL可能會明顯變慢。你必須確保MODE值被控制,否則你會得到醜陋的錯誤信息。而且,由於相同的模式運行多個命令,所以命令被複制到代碼中。

@echo off 
setlocal 
set "mode=%~1" 

call :%MODE% 
:: remainder of logic 
exit /b 

:TYPE1 
echo command A 
echo command B 
exit /b 

:TYPE2 
echo command A 
exit /b 

:TYPE3 
echo command B 
echo command C 
exit /b 

如果命令A和/或B和/或C是命令的複雜的塊,則它們可以被製作成自己的標記的子例程,並要求在適當情況下。這將防止複雜邏輯的複製。

2)FINDSTR的另一種可能性是有條件的命令執行,但這會比IF更慢,並且更加尷尬。唯一的好處是它不需要額外的變量來實現「或」邏輯。

@echo off 
setlocal 
set "mode=%~1" 

echo %mode%|>nul findstr "TYPE1 TYPE2" && echo command A 
echo %mode%|>nul findstr "TYPE1 TYPE3" && echo command B 
echo %mode%|>nul findstr "TYPE3"  && echo command C 

請注意,如果您的模式類似於BC和ABCD,那麼上述內容將不起作用,因爲BC包含在ABCD內。這可以通過引入一些括號來處理。

@echo off 
setlocal 
set "mode=%~1" 

echo {%mode%}|>nul findstr "{TYPE1} {TYPE2}" && echo command A 
echo {%mode%}|>nul findstr "{TYPE1} {TYPE3}" && echo command B 
echo {%mode%}|>nul findstr "{TYPE3}"   && echo command C 

最後,你可以使用MC ND的一個簡單的宏的想法,使上面看起來更優雅。

@echo off 
setlocal 
set "mode=%~1" 

set "whenMode=echo {%mode%}|>nul findstr" 

%whenMode% "{TYPE1} {TYPE2}" && echo command A 
%whenMode% "{TYPE1} {TYPE3}" && echo command B 
%whenMode% "{TYPE3}"   && echo command C 

3)你可以得到真正看中的,並使用batch macros with arguments先進的技術。這是一個good primer to the technology and development of batch macros with arguments

設置宏需要大量的神祕代碼,但一旦定義,它就很容易使用,而且速度非常快。最好的部分是它可以用於反對任何變量。在下面的例子中,我使用MODE1和MODE2。

@echo off 
setlocal disableDelayedExpansion 
set "mode1=%~1" 
set "mode2=%~2" 

:: define LF as a Line Feed (newline) character 
set ^"LF=^ 

^" Above empty line is required - do not remove 

:: define a newline with line continuation 
set ^"\n=^^^%LF%%LF%^%LF%%LF%^^" 

:: define a when macro that takes arguments 
set when=%\n% 
for %%# in (1 2) do if %%#==2 (setlocal enableDelayedExpansion^&for /f "tokens=1*" %%1 in ("!args!") do (%\n% 
    set "test= %%~2 "%\n% 
    for /f %%M in ("!%%1!") do (%\n% 
    if "!test:%%M=!" neq "!test!" (%\n% 
     endlocal%\n% 
     endlocal%\n% 
     (call)%\n% 
    ) else (%\n% 
     endlocal%\n% 
     endlocal%\n% 
     (call)%\n% 
    )%\n% 
)%\n% 
)) else setlocal^&set args= 

:: ------- End of Initialization --------------------- 

(%when% mode1 "TYPE1 TYPE2") && echo command A 
(%when% mode1 "TYPE1 TYPE3") && echo command B 
(%when% mode1 "TYPE3")  && echo command C 

(%when% mode2 "TYPE1 TYPE2") && echo command X 
(%when% mode2 "TYPE1 TYPE3") && echo command Y 
(%when% mode2 "TYPE3")  && echo command Z 
+0

不錯,你如何創建LF,帶有引號和只有一個空行,對我而言是新的 – jeb

1

我覺得最清晰和最快速的解決這個問題是通過array

@echo off 
setlocal EnableDelayedExpansion 

rem Define the array of equivalences from MODE values vs Command 
set numCommands=0 
for %%a in ("TYPE1|TYPE2=Command A" 
      "TYPE1|TYPE3=Command B" 
      "TYPE3=Command C") do (
    set /A numCommands+=1 
    set "command[!numCommands!]=%%~a" 
) 

rem Get MODE as parameter: 
set "MODE=%~1" 

rem Execute the commands in order 
for /L %%i in (1,1,%numCommands%) do (
    for /F "tokens=1,2 delims==" %%a in ("!command[%%i]!") do (
     set "options=|%%a|" 
     if "!options:|%MODE%|=!" neq "!options!" ECHO Run: %%b 
    ) 
) 

編輯:或者在更短的路,不帶陣列:

@echo off 
setlocal EnableDelayedExpansion 

set "MODE=%~1" 

for %%i in ("TYPE1|TYPE2=Command A" 
      "TYPE1|TYPE3=Command B" 
      "TYPE3=Command C") do (
    for /F "tokens=1,2 delims==" %%a in (%%i) do (
     set "options=|%%a|" 
     if "!options:|%MODE%|=!" neq "!options!" ECHO Run: %%b 
    ) 
)