批处理文件 – Windows批处理是否支持异常处理?

前端之家收集整理的这篇文章主要介绍了批处理文件 – Windows批处理是否支持异常处理?前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。
Windows批处理编程是否支持异常处理?如果没有,有没有办法有效地模拟批处理文件中的异常处理?

我想要能够在任何CALL级别的批处理脚本中“抛出异常”,并且CALL堆栈重复弹出,直到找到一个活动的“TRY块”,因此“CATCH块”可以处理异常完全进行或进行一些清理,并继续弹出CALL堆栈.如果从未处理异常,则会终止批处理,并且控制将返回到具有错误消息的命令行上下文.

已经有couple posted ways to terminate batch processing at any CALL depth,但是这些技术中没有一个允许通常通过异常处理在其他语言中提供的任何结构化清理活动.

注意:这是一个我已经知道最近才发现的好答案的情况,我想分享这个信息

Windows批处理脚本当然没有任何正式的异常处理 – 考虑到这个语言是多么原始的,这并不奇怪.我从来没有想过有效的异常处理可能被黑客入侵.

但是,在Russian site关于错误的GOTO声明的行为的一些惊人的发现(我不知道该说什么,我看不懂俄语). An English summary was posted at DosTips,行为进一步调查.

事实证明,(GOTO)2> NUL的行为几乎与EXIT / B相同,除了已经解析的代码块中的连接命令在有效返回之后仍然在CALLER的上下文中执行!

这是一个简短的例子,它演示了大部分的重点.

  1. @echo off
  2. setlocal enableDelayedExpansion
  3. set "var=Parent Value"
  4. (
  5. call :test
  6. echo This and the following line are not executed
  7. exit /b
  8. )
  9. :break
  10. echo How did I get here^^!^^!^^!^^!
  11. exit /b
  12.  
  13. :test
  14. setlocal disableDelayedExpansion
  15. set "var=Child Value"
  16. (goto) 2>nul & echo var=!var! & goto :break
  17. echo This line is not executed
  18.  
  19. :break
  20. echo This line is not executed@H_502_18@
  21. 输出

  22. var=Parent Value
  23. How did I get here!!!!@H_502_18@ 
  24.  

    这个功能是完全意想不到的,而且功能强大而有用.它已被用于:

  25.  

    >创建PrintHere.bat 这是“nix这里的文件功能的仿真”
    >创建一个RETURN.BAT utility,任何批处理“函数”可以方便地通过ENDLOCAL屏障返回任何值,几乎没有任何限制.该代码jebs original idea的丰富版本.

  26.  

    现在我也可以添加异常处理列表:-)

  27.  

    该技术依赖于一个称为EXCEPTION.BAT的批处理实用程序来定义用于指定TRY / CATCH块的环境变量“宏”,以及抛出异常.

  28.  

    在可以实现TRY / CATCH块之前,必须使用以下命令定义宏:

  29.   
  30.  
    call exception init@H_502_18@ 
  31.  

    然后TRY / CATCH块用以下语法定义:

  32.   
  33.  
    :calledRoutine
  34. setlocal
  35. %@Try%
  36.   REM normal code goes here
  37. %@EndTry%
  38. :@Catch
  39.   REM Exception handling code goes here
  40. :@EndCatch@H_502_18@ 
  41.  

    可以随时通过以下方式抛出异常:

  42.   
  43.  
    call exception throw  errorNumber  "messageString"  "locationString"@H_502_18@ 
  44.  

    当抛出异常时,它会使用(GOTO)2> NUL迭代地弹出CALL堆栈,直到它找到一个活动的TRY / CATCH,然后它分支到CATCH块并执行该代码.一系列异常属性变量可用于CATCH块:

  45.  

    > exception.Code 数字异常代码
    > exception.Msg 异常消息字符串
    > exception.Loc 描述抛出异常的位置的字符串
    > exception.Stack 一个从CATCH块跟踪调用堆栈(或命令行,如果没有被捕获)的字符串,一直到异常来源.

  46.  

    如果异常被完全处理,则应该通过调用异常清除来清除异常,并且该脚本正常进行.如果异常没有被完全处理,那么一个新的异常可以抛出一个全新的异常.堆栈或旧的堆栈可以保存与

  47.   
  48.  
    call exception rethrow  errorNumber  "messageString"  "locationString"@H_502_18@ 
  49.  

    如果未处理异常,则会打印一个“未处理的异常”消息,包括四个异常属性,所有批处理都将终止,并将控制返回到命令行上下文.

  50.  

    以下是使所有这些可能的代码 完整的文档嵌入在脚本中,并可以通过异常帮助或异常/?从命令行获取.

  51.  

    EXCEPTION.BAT

  52.   
  53.  
    ::EXCEPTION.BAT Version 1.4
  54. ::
  55. :: Provides exception handling for Windows batch scripts.
  56. ::
  57. :: Designed and written by Dave Benham,with important contributions from
  58. :: DosTips users jeb and siberia-man
  59. ::
  60. :: Full documentation is at the bottom of this script
  61. ::
  62. :: History:
  63. ::   v1.4 2016-08-16  Improved detection of command line delayed expansion
  64. ::                    using an original idea by jeb
  65. ::   v1.3 2015-12-12  Added paged help option via MORE
  66. ::   v1.2 2015-07-16  Use COMSPEC instead of OS to detect delayed expansion
  67. ::   v1.1 2015-07-03  Preserve ! in exception attributes when delayed expansion enabled
  68. ::   v1.0 2015-06-26  Initial versioned release with embedded documentation
  69. ::
  70. @echo off
  71. if "%~1" equ "/??" goto pagedHelp
  72. if "%~1" equ "/?" goto help
  73. if "%~1" equ "" goto help
  74. shift /1 & goto %1
  75. :throw  errCode  errMsg  errLoc
  76. set "exception.Stack="
  77. :: Fall through to :rethrow
  78. :rethrow  errCode  errMsg  errLoc
  79. setlocal disableDelayedExpansion
  80. if not defined exception.Restart set "exception.Stack=[%~1:%~2] %exception.Stack%"
  81. for /f "delims=" %%1 in ("%~1") do for /f "delims=" %%2 in ("%~2") do for /f "delims=" %%3 in ("%~3") do (
  82.   setlocal enableDelayedExpansion
  83.   for /l %%# in (1 1 10) do for /f "delims=" %%S in (" !exception.Stack!") do (
  84.     (goto) 2>NUL
  85.     setlocal enableDelayedExpansion
  86.     if "!!" equ "" (
  87.       endlocal
  88.       setlocal disableDelayedExpansion
  89.       call set "funcName=%%~0"
  90.       call set "batName=%%~f0"
  91.       if defined exception.Restart (set "exception.Restart=") else call set "exception.Stack=%%funcName%%%%S"
  92.       setlocal EnableDelayedExpansion
  93.       if !exception.Try! == !batName!:!funcName! (
  94.         endlocal
  95.         endlocal
  96.         set "exception.Code=%%1"
  97.         if "!!" equ "" (
  98.           call "%~f0" setDelayed
  99.         ) else (
  100.           set "exception.Msg=%%2"
  101.           set "exception.Loc=%%3"
  102.           set "exception.Stack=%%S"
  103.         )
  104.         set "exception.Try="
  105.         (CALL )
  106.         goto :@Catch
  107.       )
  108.     ) else (
  109.       for %%V in (Code Msg Loc Stack Try Restart) do set "exception.%%V="
  110.       if "^!^" equ "^!" (
  111.         call "%~f0" showDelayed
  112.       ) else (
  113.         echo(
  114.         echo Unhandled batch exception:
  115.         echo   Code = %%1
  116.         echo   Msg  = %%2
  117.         echo   Loc  = %%3
  118.         echo   Stack=%%S
  119.       )
  120.       echo on
  121.       call "%~f0" Kill
  122.     )>&2
  123.   )
  124.   set exception.Restart=1
  125.   setlocal disableDelayedExpansion
  126.   call "%~f0" rethrow %1 %2 %3
  127. )
  128. :: Never reaches here
  129. :init
  130. set "@Try=call set exception.Try=%%~f0:%%~0"
  131. set "@EndTry=set "exception.Try=" & goto :@endCatch"
  132. :: Fall through to :clear
  133. :clear
  134. for %%V in (Code Msg Loc Stack Restart Try) do set "exception.%%V="
  135. exit /b
  136. :Kill - Cease all processing,ignoring any remaining cached commands
  137. setlocal disableDelayedExpansion
  138. if not exist "%temp%\Kill.Yes" call :buildYes
  139. call :CtrlC <"%temp%\Kill.Yes" 1>nul 2>&1
  140. :CtrlC
  141. @cmd /c exit -1073741510
  142. :buildYes - Establish a Yes file for the language used by the OS
  143. pushd "%temp%"
  144. set "yes="
  145. copy nul Kill.Yes >nul
  146. for /f "delims=(/ tokens=2" %%Y in (
  147.   '"copy /-y nul Kill.Yes <nul"'
  148. ) do if not defined yes set "yes=%%Y"
  149. echo %yes%>Kill.Yes
  150. popd
  151. exit /b
  152. :setDelayed
  153. setLocal disableDelayedExpansion
  154. for %%. in (.) do (
  155.   set "v2=%%2"
  156.   set "v3=%%3"
  157.   set "vS=%%S"
  158. )
  159. (
  160.   endlocal
  161.   set "exception.Msg=%v2:!=^!%"
  162.   set "exception.Loc=%v3:!=^!%"
  163.   set "exception.Stack=%vS:!=^!%"
  164. )
  165. exit /b
  166. :showDelayed -
  167. setLocal disableDelayedExpansion
  168. for %%. in (.) do (
  169.   set "v2=%%2"
  170.   set "v3=%%3"
  171.   set "vS=%%S"
  172. )
  173. for /f "delims=" %%2 in ("%v2:!=^!%") do for /f "delims=" %%3 in ("%v3:!=^!%") do for /f "delims=" %%S in ("%vS:!=^!%") do (
  174.   endlocal
  175.   echo(
  176.   echo Unhandled batch exception:
  177.   echo   Code = %%1
  178.   echo   Msg  = %%2
  179.   echo   Loc  = %%3
  180.   echo   Stack=%%S
  181. )
  182. exit /b
  183. :-?
  184. :help
  185. setlocal disableDelayedExpansion
  186. for /f "delims=:" %%N in ('findstr /rbn ":::DOCUMENTATION:::" "%~f0"') do set "skip=%%N"
  187. for /f "skip=%skip% tokens=1* delims=:" %%A in ('findstr /n "^" "%~f0"') do echo(%%B
  188. exit /b
  189. :-??
  190. :pagedHelp
  191. setlocal disableDelayedExpansion
  192. for /f "delims=:" %%N in ('findstr /rbn ":::DOCUMENTATION:::" "%~f0"') do set "skip=%%N"
  193. ((for /f "skip=%skip% tokens=1* delims=:" %%A in ('findstr /n "^" "%~f0"') do @echo(%%B)|more /e) 2>nul
  194. exit /b
  195. :-v
  196. :/v
  197. :version
  198. echo(
  199. for /f "delims=:" %%A in ('findstr "^::EXCEPTION.BAT" "%~f0"') do echo %%A
  200. exit /b
  201. :::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
  202. :::DOCUMENTATION:::
  203. EXCEPTION.BAT is a pure batch script utility that provides robust exception
  204. handling within batch scripts. It enables code to be placed in TRY/CATCH blocks.
  205. If no exception is thrown,then only code within the TRY block is executed.
  206. If an exception is thrown,the batch CALL stack is popped repeatedly until it
  207. reaches an active TRY block,at which point control is passed to the associated
  208. CATCH block and normal processing resumes from that point. Code within a CATCH
  209. block is ignored unless an exception is thrown.
  210. An exception may be caught in a different script from where it was thrown.
  211. If no active TRY is found after throwing an exception,then an unhandled
  212. exception message is printed to stderr,all processing is terminated within the
  213. current CMD shell,and control is returned to the shell command line.
  214. TRY blocks are specified using macros. ObvIoUsly the macros must be defined
  215. before they can be used. The TRY macros are defined using the following CALL
  216.     call exception init
  217. Besides defining @Try and @EndTry,the init routine also explicitly clears any
  218. residual exception that may have been left by prior processing.
  219. A TRY/CATCH block is structured as follows:
  220.     %@Try%
  221.       REM any normal code goes here
  222.     %@EndTry%
  223.     :@Catch
  224.       REM exception handling code goes here
  225.     :@EndCatch
  226. - Every TRY must have an associated CATCH.
  227. - TRY/CATCH blocks cannot be nested.
  228. - Any script or :labeled routine that uses TRY/CATCH must have at least one
  229.   SETLOCAL prior to the appearance of the first TRY.
  230. - TRY/CATCH blocks use labels,so they should not be placed within parentheses.
  231.   It can be done,but the parentheses block is broken when control is passed to
  232.   the :@Catch or :@EndCatch label,and the code becomes difficult to interpret
  233.   and maintain.
  234. - Any valid code can be used within a TRY or CATCH block,including CALL,GOTO,:labels,and balanced parentheses. However,GOTO cannot be used to leave a
  235.   TRY block. GOTO can only be used within a TRY block if the label appears
  236.   within the same TRY block.
  237. - GOTO must never transfer control from outside TRY/CATCH to within a TRY or
  238.   CATCH block.
  239. - CALL should not be used to call a label within a TRY or CATCH block.
  240. - CALLed routines containing TRY/CATCH must have labels that are unique within
  241.   the script. This is generally good batch programming practice anyway.
  242.   It is OK for different scripts to share :label names.
  243. - If a script or routine recursively CALLs itself and contains TRY/CATCH,then
  244.   it must not throw an exception until after execution of the first %@Try%
  245. Exceptions are thrown by using
  246.     call exception throw  Code  Message  Location
  247. where
  248.     Code = The numeric code value for the exception.
  249.     Message = A description of the exception.
  250.     Location = A string that helps identify where the exception occurred.
  251.                Any value may be used. A good generic value is "%~f0[%~0]",which expands to the full path of the currently executing
  252.                script,followed by the currently executing routine name
  253.                within square brackets.
  254. The Message and Location values must be quoted if they contain spaces or poison
  255. characters like & | < >. The values must not contain additional internal quotes,and they must not contain a caret ^.
  256. The following variables will be defined for use by the CATCH block:
  257.   exception.Code  = the Code value
  258.   exception.Msg   = the Message value
  259.   exception.Loc   = the Location value
  260.   exception.Stack = traces the call stack from the CATCH block (or command line
  261.                     if not caught),all the way to the exception.
  262. If the exception is not caught,then all four values are printed as part of the
  263. "unhandled exception" message,and the exception variables are not defined.
  264. A CATCH block should always do ONE of the following at the end:
  265. - If the exception has been handled and processing can continue,then clear the
  266.   exception definition by using
  267.     call exception clear
  268.   Clear should never be used within a Try block.
  269. - If the exception has not been fully handled,then a new exception should be
  270.   thrown which can be caught by a higher level CATCH. You can throw a new
  271.   exception using the normal THROW,which will clear exception.Stack and any
  272.   higher CATCH will have no awareness of the original exception.
  273.   Alternatively,you may rethrow an exception and preserve the exeption stack
  274.   all the way to the original exception:
  275.     call exception rethrow  Code  Message  Location
  276.   It is your choice as to whether you want to pass the original Code and/or
  277.   Message and/or Location. Either way,the stack will preserve all exceptions
  278.   if rethrow is used.
  279.   Rethrow should only be used within a CATCH block.
  280. One last restriction - the full path to EXCEPTION.BAT must not include ! or ^.
  281. This documentation can be accessed via the following commands
  282.     constant stream:   exception /?   OR  exception help
  283.     paged via MORE:    exception /??  OR  exception pagedHelp
  284. The version of this utility can be accessed via
  285.     exception /v  OR  exception version
  286. EXCEPTION.BAT was designed and written by Dave Benham,with important
  287. contributions from DosTips users jeb and siberia-man.
  288. Development history can be traced at:
  289.   http://www.dostips.com/forum/viewtopic.PHP?f=3&t=6497@H_502_18@ 
  290.  

    以下是测试EXCEPTION.BAT功能的脚本.该脚本递归调用自身7次.每个迭代都有两个CALL,一个到a标签,表示正常的异常传播,另一个到演示脚本CALL的异常传播的脚本.

  291.  

    当从递归调用返回时,如果迭代计数是3的倍数(迭代36),则会抛出异常.

  292.  

    每个CALL都有自己的异常处理程序,通常会报告异常,然后重新抛出一个修改的异常.但如果迭代次数5,那么处理异常并恢复正常处理.

  293.   
  294.  
    @echo off
  295. :: Main
  296. setlocal enableDelayedExpansion
  297. if not defined @Try call exception init
  298. set /a cnt+=1
  299. echo Main Iteration %cnt% - Calling :Sub
  300. %@Try%
  301. (
  302.   call :Sub
  303.   call echo Main Iteration %cnt% - :Sub returned %%errorlevel%%
  304. )
  305. %@EndTry%
  306. :@Catch
  307.   setlocal enableDelayedExpansion
  308.   echo(
  309.   echo Main Iteration %cnt% - Exception detected:
  310.   echo   Code     = !exception.code!
  311.   echo   Message  = !exception.msg!
  312.   echo   Location = !exception.loc!
  313.   echo Rethrowing modified exception
  314.   echo(
  315.   endlocal
  316.   call exception rethrow -%cnt% "Main Exception^!" "%~f0<%~0>"
  317. :@EndCatch
  318. echo Main Iteration %cnt% - Exit
  319. exit /b %cnt%
  320. :Sub
  321. setlocal
  322. echo :Sub Iteration %cnt% - Start
  323. %@Try%
  324.   if %cnt% lss 7 (
  325.     echo :Sub Iteration %cnt% - Calling "%~f0"
  326.     call "%~f0"
  327.     %= Show any non-exception return code (demonstrate ERRORLEVEL is preserved if no exception) =%
  328.     call echo :Sub Iteration %cnt% - testException returned %%errorlevel%%
  329.   )
  330.   %= Throw an exception if the iteration count is a multiple of 3 =%
  331.   set /a "1/(cnt%%3)" 2>nul || (
  332.     echo Throwing exception
  333.     call exception throw -%cnt% "Divide by 0 exception^!" "%~f0<%~0>"
  334.   )
  335. %@EndTry%
  336. :@Catch
  337.   setlocal enableDelayedExpansion
  338.   echo(
  339.   echo :Sub Iteration %cnt% - Exception detected:
  340.   echo   Code     = !exception.code!
  341.   echo   Message  = !exception.msg!
  342.   echo   Location = !exception.loc!
  343.   endlocal
  344.   %= Handle the exception if iteration count is a multiple of 5,else rethrow it with new properties =%
  345.   set /a "1/(cnt%%5)" 2>nul && (
  346.     echo Rethrowing modified exception
  347.     echo(
  348.     call exception rethrow -%cnt% ":Sub Exception^!" "%~f0<%~0>"
  349.   ) || (
  350.     call exception clear
  351.     echo Exception handled
  352.     echo(
  353.   )
  354. :@EndCatch
  355. echo :Sub Iteration %cnt% - Exit
  356. exit /b %cnt%@H_502_18@ 
  357.  

    输出

  358.   
  359.  
    Main Iteration 1 - Calling :Sub
  360. :Sub Iteration 1 - Start
  361. :Sub Iteration 1 - Calling "C:\test\testException.bat"
  362. Main Iteration 2 - Calling :Sub
  363. :Sub Iteration 2 - Start
  364. :Sub Iteration 2 - Calling "C:\test\testException.bat"
  365. Main Iteration 3 - Calling :Sub
  366. :Sub Iteration 3 - Start
  367. :Sub Iteration 3 - Calling "C:\test\testException.bat"
  368. Main Iteration 4 - Calling :Sub
  369. :Sub Iteration 4 - Start
  370. :Sub Iteration 4 - Calling "C:\test\testException.bat"
  371. Main Iteration 5 - Calling :Sub
  372. :Sub Iteration 5 - Start
  373. :Sub Iteration 5 - Calling "C:\test\testException.bat"
  374. Main Iteration 6 - Calling :Sub
  375. :Sub Iteration 6 - Start
  376. :Sub Iteration 6 - Calling "C:\test\testException.bat"
  377. Main Iteration 7 - Calling :Sub
  378. :Sub Iteration 7 - Start
  379. :Sub Iteration 7 - Exit
  380. Main Iteration 7 - :Sub returned 7
  381. Main Iteration 7 - Exit
  382. :Sub Iteration 6 - testException returned 7
  383. Throwing exception
  384. :Sub Iteration 6 - Exception detected:
  385.   Code     = -6
  386.   Message  = Divide by 0 exception!
  387.   Location = C:\test\testException.bat<:Sub>
  388. Rethrowing modified exception
  389. Main Iteration 6 - Exception detected:
  390.   Code     = -6
  391.   Message  = :Sub Exception!
  392.   Location = C:\test\testException.bat<:Sub>
  393. Rethrowing modified exception
  394. :Sub Iteration 5 - Exception detected:
  395.   Code     = -6
  396.   Message  = Main Exception!
  397.   Location = C:\test\testException.bat<C:\test\testException.bat>
  398. Exception handled
  399. :Sub Iteration 5 - Exit
  400. Main Iteration 5 - :Sub returned 5
  401. Main Iteration 5 - Exit
  402. :Sub Iteration 4 - testException returned 5
  403. :Sub Iteration 4 - Exit
  404. Main Iteration 4 - :Sub returned 4
  405. Main Iteration 4 - Exit
  406. :Sub Iteration 3 - testException returned 4
  407. Throwing exception
  408. :Sub Iteration 3 - Exception detected:
  409.   Code     = -3
  410.   Message  = Divide by 0 exception!
  411.   Location = C:\test\testException.bat<:Sub>
  412. Rethrowing modified exception
  413. Main Iteration 3 - Exception detected:
  414.   Code     = -3
  415.   Message  = :Sub Exception!
  416.   Location = C:\test\testException.bat<:Sub>
  417. Rethrowing modified exception
  418. :Sub Iteration 2 - Exception detected:
  419.   Code     = -3
  420.   Message  = Main Exception!
  421.   Location = C:\test\testException.bat<C:\test\testException.bat>
  422. Rethrowing modified exception
  423. Main Iteration 2 - Exception detected:
  424.   Code     = -2
  425.   Message  = :Sub Exception!
  426.   Location = C:\test\testException.bat<:Sub>
  427. Rethrowing modified exception
  428. :Sub Iteration 1 - Exception detected:
  429.   Code     = -2
  430.   Message  = Main Exception!
  431.   Location = C:\test\testException.bat<C:\test\testException.bat>
  432. Rethrowing modified exception
  433. Main Iteration 1 - Exception detected:
  434.   Code     = -1
  435.   Message  = :Sub Exception!
  436.   Location = C:\test\testException.bat<:Sub>
  437. Rethrowing modified exception
  438. Unhandled batch exception:
  439.   Code = -1
  440.   Msg  = Main Exception!
  441.   Loc  = C:\test\testException.bat<testException>
  442.   Stack= testException [-1:Main Exception!]  :Sub [-1::Sub Exception!]  C:\test\testException.bat [-2:Main Exception!]  :Sub [-2::Sub Exception!]  C:\test\testException.bat [-3:Main Exception!]  :Sub [-3::Sub Exception!]  [-3:Divide by 0 exception!]@H_502_18@ 
  443.  

    最后,这里是一系列简单的脚本,显示了即使中间脚本对它们没有任何知识也可以有效地使用异常!

  444.  

    开始使用一个简单的分割脚本实用程序,分割两个数字并打印结果:

  445.  

    divide.bat

  446.   
  447.  
    :: divide.bat  numerator  divisor
  448. @echo off
  449. setlocal
  450. set /a result=%1 / %2 2>nul || call exception throw -100 "Division exception" "divide.bat"
  451. echo %1 / %2 = %result%
  452. exit /b@H_502_18@ 
  453.  

    请注意,如果脚本检测到错误,脚本会引发异常,但是它不会捕获异常.

  454.  

    现在我将编写一个对批处理异常完全天真的分割测试工具.

  455.  

    testDivide.bat

  456.   
  457.  
    @echo off
  458. for /l %%N in (4 -1 0) do call divide 12 %%N
  459. echo Finished successfully!@H_502_18@ 
  460.  

    OUTPUT

  461.   
  462.  
    C:\test>testDivide
  463. 12 / 4 = 3
  464. 12 / 3 = 4
  465. 12 / 2 = 6
  466. 12 / 1 = 12
  467. Unhandled batch exception:
  468.   Code = -100
  469.   Msg  = Division exception
  470.   Loc  = divide.bat
  471.   Stack= testDivide divide [-100:Division exception]@H_502_18@ 
  472.  

    请注意,由于没有处理由divide.bat引发的异常,最终的ECHO将不会执行.

  473.  

    最后我会写一个主脚本,调用天真的testDivide并正确处理异常:

  474.  

    master.bat

  475.   
  476.  
    @echo off
  477. setlocal
  478. call exception init
  479. %@Try%
  480.   call testDivide
  481. %@EndTry%
  482. :@Catch
  483.   echo %exception.Msg% detected and handled
  484.   call exception clear
  485. :@EndCatch
  486. echo Finished Successfully!@H_502_18@ 
  487.  

    输出

  488.   
  489.  
    C:\test>master
  490. 12 / 4 = 3
  491. 12 / 3 = 4
  492. 12 / 2 = 6
  493. 12 / 1 = 12
  494. Division exception detected and handled
  495. Finished Successfully!@H_502_18@ 
  496.  

    主脚本能够成功地捕获由divide.bat引发的异常,即使它必须通过testDivide.bat,它不了解异常.很酷 :-)

  497.  

    现在,这并不是所有与错误处理有关的事情的灵丹妙药:

  498.  

    >有许多语法和代码布局限制,在内置文档中已经完全描述.但没有什么太糟糕.
    >没有办法自动将所有错误视为例外.所有异常必须由代码显式抛出.这可能是一件好事,因为错误报告是按惯例处理的 没有严格的规则.一些程序不符合惯例.例如,HELP ValidCommand返回ERRORLEVEL 1,这通常意味着一个错误,而HELP InvalidCommand返回ERRORLEVEL 0,这意味着成功.
    >此批处理异常技术无法捕获并处理致命的运行时错误.例如GOTONonExistentLabel仍然会立即终止所有批处理,没有任何机会来捕获错误.

  499.  

    您可以在http://www.dostips.com/forum/viewtopic.php?f=3&t=6497跟随EXCEPTION.BAT的发展.将来会发布任何未来的发展.我可能不会更新此StackOverflow文章.

猜你在找的Windows相关文章