提问者:小点点

带有分支的批处理文件-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

共3个答案

匿名用户

@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

null

@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

匿名用户

首先,我认为谨慎的做法是展示如何使用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

现在介绍IF的可能替代方案

1)我能想到的一个半实用的方法是使用模式作为标签,但我不喜欢它。不必要的使用CALL会显着降低速度。你必须确保模式值受到控制,否则你会得到难看的错误消息。此外,由于同一个模式运行多个命令,命令会在代码中复制。

@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慢,也更尴尬,唯一的好处是它不需要额外的变量来实现OR逻辑。

@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)你可以非常有趣地使用带有参数的批处理宏的高级技术。这里是一本很好的带参数的批处理宏的技术和开发的入门读物。

设置宏需要大量的神秘代码,但是一旦定义,它就非常容易使用,而且速度非常快。最好的部分是它可以用来对付任何变量。在下面的示例中,我将它与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

匿名用户

我认为这个问题最清晰,最快的解决方案是通过数组:

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