我有一个批处理文件,它接受动作模式作为参数,并根据它以特定的顺序运行几个命令,我想知道除了在其中有很多很多的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
@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
)
)