Windows batch prend-il en charge la gestion des exceptions?

La programmation par lots Windows prend-elle en charge la gestion des exceptions? Sinon, existe-t-il un moyen d'émuler efficacement la gestion des exceptions dans les fichiers batch?

Je voudrais pouvoir " lancer une exception "n'importe où dans un script batch, à n'importe quel niveau D'appel, et faire apparaître la pile D'appels à plusieurs reprises jusqu'à ce qu'elle trouve un" bloc D'essai "actif, après quoi un" bloc de capture " peut gérer l'exception complètement et continuer, ou faire un peu de nettoyage et continuer Si l'exception n'est jamais géré, le traitement par lots est terminé et control retourne au contexte de ligne de commande avec un message d'erreur.

Il existe déjà quelques moyens affichés pour terminer le traitement par lots à n'importe quelle profondeur d'appel, mais aucune de ces techniques ne permet une activité de nettoyage structuré qui serait normalement fournie dans d'autres langues via la gestion des exceptions.

Note: C'est un cas où je connais déjà une bonne réponse qui a été récemment découvert, et je veux partager l'info

22
demandé sur Community 2015-07-16 07:24:00

3 réponses

Windows batch scripting n'a certainement pas de gestion formelle des exceptions-ce qui n'est pas surprenant compte tenu de la primitive du langage. Jamais dans mes rêves les plus fous n'ai-je jamais pensé qu'une gestion efficace des exceptions pourrait être piratée.

Mais ensuite quelques découvertes étonnantes ont été faites sur un site russe concernant le comportement d'une déclaration Goto erronée (je n'ai aucune idée de ce qui est dit, Je ne peux pas lire le russe). un résumé en anglais a été publié sur DosTips , et le comportement a été étudié.

Il s'avère que (GOTO) 2>NUL se comporte presque de manière identique à EXIT / B, sauf que les commandes concaténées dans un bloc de code déjà analysé sont toujours exécutées après le retour effectif, dans le contexte de L'appelant!

Voici un petit exemple qui montre la plupart des points saillants.

@echo off
setlocal enableDelayedExpansion
set "var=Parent Value"
(
  call :test
  echo This and the following line are not executed
  exit /b
)
:break
echo How did I get here^^!^^!^^!^^!
exit /b

:test
setlocal disableDelayedExpansion
set "var=Child Value"
(goto) 2>nul & echo var=!var! & goto :break
echo This line is not executed

:break
echo This line is not executed

-- sortie --

var=Parent Value
How did I get here!!!!

Cette fonctionnalité est totalement inattendue, et incroyablement puissante et utile. Il a été utilisé pour:

  • Créer PrintHere.bat - une émulation de la fonctionnalité ' nix here document
  • crée un retour .Utilitaire BAT que toute "fonction" de lot peut facilement appeler pour renvoyer n'importe quelle valeur à travers la barrière ENDLOCAL, avec pratiquement aucune limitation. Le code est une version étoffée de l'idée originale de jeb .

Maintenant, je peux également ajouter la gestion des exceptions à la liste: -)

La technique repose sur un lot utilitaire appelé EXCEPTION.BAT pour définir des variables d'environnement "macros" qui sont utilisées pour spécifier des blocs TRY/CATCH, ainsi que pour lancer des exceptions.

Avant qu'un bloc TRY/CATCH puisse être implémenté, les macros doivent être définies en utilisant:

call exception init

Ensuite, les blocs TRY/CATCH sont définis avec la syntaxe suivante:

:calledRoutine
setlocal
%@Try%
  REM normal code goes here
%@EndTry%
:@Catch
  REM Exception handling code goes here
:@EndCatch

Les Exceptions peuvent être levées à tout moment via:

call exception throw  errorNumber  "messageString"  "locationString"

Lorsqu'une exception est levée, elle affiche la pile D'appels de manière itérative en utilisant (GOTO) 2>NUL jusqu'à ce qu'elle trouve un active TRY / CATCH, après quoi il se branche au bloc CATCH et exécute ce code. Une série de variables d'attribut d'exception sont disponibles pour le bloc CATCH:

  • exception.Code - le code d'exception numérique
  • exception.Msg-la chaîne de message d'exception
  • exception.Loc-la chaîne décrivant l'emplacement où l'exception a été levée
  • exception.Stack-une chaîne qui trace la pile d'appels à partir du bloc CATCH (ou de la ligne de commande si elle n'est pas interceptée), tous le chemin vers l'origine de l'exception.

Si l'exception est entièrement gérée, l'exception doit être effacée via call exception clear, et le script continue normalement. Si l'exception n'est pas entièrement gérée, une nouvelle exception peut être levée avec une toute nouvelle exception.Pile, ou l'ancienne pile peut être conservée avec

call exception rethrow  errorNumber  "messageString"  "locationString"

Si une exception n'est pas gérée, un message" exception non gérée " est imprimé, y compris les quatre attributs d'exception, tout le traitement par lots est terminé, et le contrôle est renvoyé au contexte de ligne de commande.

Voici le code qui rend tout cela possible - la documentation complète est intégrée dans le script et disponible à partir de la ligne de commande via exception help ou exception /?.

EXCEPTION à la règle.MTD

::EXCEPTION.BAT Version 1.4
::
:: Provides exception handling for Windows batch scripts.
::
:: Designed and written by Dave Benham, with important contributions from
:: DosTips users jeb and siberia-man
::
:: Full documentation is at the bottom of this script
::
:: History:
::   v1.4 2016-08-16  Improved detection of command line delayed expansion
::                    using an original idea by jeb
::   v1.3 2015-12-12  Added paged help option via MORE
::   v1.2 2015-07-16  Use COMSPEC instead of OS to detect delayed expansion
::   v1.1 2015-07-03  Preserve ! in exception attributes when delayed expansion enabled
::   v1.0 2015-06-26  Initial versioned release with embedded documentation
::
@echo off
if "%~1" equ "/??" goto pagedHelp
if "%~1" equ "/?" goto help
if "%~1" equ "" goto help
shift /1 & goto %1


:throw  errCode  errMsg  errLoc
set "exception.Stack="
:: Fall through to :rethrow


:rethrow  errCode  errMsg  errLoc
setlocal disableDelayedExpansion
if not defined exception.Restart set "exception.Stack=[%~1:%~2] %exception.Stack%"
for /f "delims=" %%1 in ("%~1") do for /f "delims=" %%2 in ("%~2") do for /f "delims=" %%3 in ("%~3") do (
  setlocal enableDelayedExpansion
  for /l %%# in (1 1 10) do for /f "delims=" %%S in (" !exception.Stack!") do (
    (goto) 2>NUL
    setlocal enableDelayedExpansion
    if "!!" equ "" (
      endlocal
      setlocal disableDelayedExpansion
      call set "funcName=%%~0"
      call set "batName=%%~f0"
      if defined exception.Restart (set "exception.Restart=") else call set "exception.Stack=%%funcName%%%%S"
      setlocal EnableDelayedExpansion
      if !exception.Try! == !batName!:!funcName! (
        endlocal
        endlocal
        set "exception.Code=%%1"
        if "!!" equ "" (
          call "%~f0" setDelayed
        ) else (
          set "exception.Msg=%%2"
          set "exception.Loc=%%3"
          set "exception.Stack=%%S"
        )
        set "exception.Try="
        (CALL )
        goto :@Catch
      )
    ) else (
      for %%V in (Code Msg Loc Stack Try Restart) do set "exception.%%V="
      if "^!^" equ "^!" (
        call "%~f0" showDelayed
      ) else (
        echo(
        echo Unhandled batch exception:
        echo   Code = %%1
        echo   Msg  = %%2
        echo   Loc  = %%3
        echo   Stack=%%S
      )
      echo on
      call "%~f0" Kill
    )>&2
  )
  set exception.Restart=1
  setlocal disableDelayedExpansion
  call "%~f0" rethrow %1 %2 %3
)
:: Never reaches here


:init
set "@Try=call set exception.Try=%%~f0:%%~0"
set "@EndTry=set "exception.Try=" & goto :@endCatch"
:: Fall through to :clear


:clear
for %%V in (Code Msg Loc Stack Restart Try) do set "exception.%%V="
exit /b


:Kill - Cease all processing, ignoring any remaining cached commands
setlocal disableDelayedExpansion
if not exist "%temp%\Kill.Yes" call :buildYes
call :CtrlC <"%temp%\Kill.Yes" 1>nul 2>&1
:CtrlC
@cmd /c exit -1073741510

:buildYes - Establish a Yes file for the language used by the OS
pushd "%temp%"
set "yes="
copy nul Kill.Yes >nul
for /f "delims=(/ tokens=2" %%Y in (
  '"copy /-y nul Kill.Yes <nul"'
) do if not defined yes set "yes=%%Y"
echo %yes%>Kill.Yes
popd
exit /b


:setDelayed
setLocal disableDelayedExpansion
for %%. in (.) do (
  set "v2=%%2"
  set "v3=%%3"
  set "vS=%%S"
)
(
  endlocal
  set "exception.Msg=%v2:!=^!%"
  set "exception.Loc=%v3:!=^!%"
  set "exception.Stack=%vS:!=^!%"
)
exit /b


:showDelayed -
setLocal disableDelayedExpansion
for %%. in (.) do (
  set "v2=%%2"
  set "v3=%%3"
  set "vS=%%S"
)
for /f "delims=" %%2 in ("%v2:!=^!%") do for /f "delims=" %%3 in ("%v3:!=^!%") do for /f "delims=" %%S in ("%vS:!=^!%") do (
  endlocal
  echo(
  echo Unhandled batch exception:
  echo   Code = %%1
  echo   Msg  = %%2
  echo   Loc  = %%3
  echo   Stack=%%S
)
exit /b


:-?
:help
setlocal disableDelayedExpansion
for /f "delims=:" %%N in ('findstr /rbn ":::DOCUMENTATION:::" "%~f0"') do set "skip=%%N"
for /f "skip=%skip% tokens=1* delims=:" %%A in ('findstr /n "^" "%~f0"') do echo(%%B
exit /b


:-??
:pagedHelp
setlocal disableDelayedExpansion
for /f "delims=:" %%N in ('findstr /rbn ":::DOCUMENTATION:::" "%~f0"') do set "skip=%%N"
((for /f "skip=%skip% tokens=1* delims=:" %%A in ('findstr /n "^" "%~f0"') do @echo(%%B)|more /e) 2>nul
exit /b


:-v
:/v
:version
echo(
for /f "delims=:" %%A in ('findstr "^::EXCEPTION.BAT" "%~f0"') do echo %%A
exit /b


:::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::::
:::DOCUMENTATION:::

EXCEPTION.BAT is a pure batch script utility that provides robust exception
handling within batch scripts. It enables code to be placed in TRY/CATCH blocks.
If no exception is thrown, then only code within the TRY block is executed.
If an exception is thrown, the batch CALL stack is popped repeatedly until it
reaches an active TRY block, at which point control is passed to the associated
CATCH block and normal processing resumes from that point. Code within a CATCH
block is ignored unless an exception is thrown.

An exception may be caught in a different script from where it was thrown.

If no active TRY is found after throwing an exception, then an unhandled
exception message is printed to stderr, all processing is terminated within the
current CMD shell, and control is returned to the shell command line.

TRY blocks are specified using macros. Obviously the macros must be defined
before they can be used. The TRY macros are defined using the following CALL

    call exception init

Besides defining @Try and @EndTry, the init routine also explicitly clears any
residual exception that may have been left by prior processing.

A TRY/CATCH block is structured as follows:

    %@Try%
      REM any normal code goes here
    %@EndTry%
    :@Catch
      REM exception handling code goes here
    :@EndCatch

- Every TRY must have an associated CATCH.

- TRY/CATCH blocks cannot be nested.

- Any script or :labeled routine that uses TRY/CATCH must have at least one
  SETLOCAL prior to the appearance of the first TRY.

- TRY/CATCH blocks use labels, so they should not be placed within parentheses.
  It can be done, but the parentheses block is broken when control is passed to
  the :@Catch or :@EndCatch label, and the code becomes difficult to interpret
  and maintain.

- 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
  TRY block. GOTO can only be used within a TRY block if the label appears
  within the same TRY block.

- GOTO must never transfer control from outside TRY/CATCH to within a TRY or
  CATCH block.

- CALL should not be used to call a label within a TRY or CATCH block.

- CALLed routines containing TRY/CATCH must have labels that are unique within
  the script. This is generally good batch programming practice anyway.
  It is OK for different scripts to share :label names.

- If a script or routine recursively CALLs itself and contains TRY/CATCH, then
  it must not throw an exception until after execution of the first %@Try%

Exceptions are thrown by using

    call exception throw  Code  Message  Location

where

    Code = The numeric code value for the exception.

    Message = A description of the exception.

    Location = A string that helps identify where the exception occurred.
               Any value may be used. A good generic value is "%~f0[%~0]",
               which expands to the full path of the currently executing
               script, followed by the currently executing routine name
               within square brackets.

The Message and Location values must be quoted if they contain spaces or poison
characters like & | < >. The values must not contain additional internal quotes,
and they must not contain a caret ^.

The following variables will be defined for use by the CATCH block:

  exception.Code  = the Code value
  exception.Msg   = the Message value
  exception.Loc   = the Location value
  exception.Stack = traces the call stack from the CATCH block (or command line
                    if not caught), all the way to the exception.

If the exception is not caught, then all four values are printed as part of the
"unhandled exception" message, and the exception variables are not defined.

A CATCH block should always do ONE of the following at the end:

- If the exception has been handled and processing can continue, then clear the
  exception definition by using

    call exception clear

  Clear should never be used within a Try block.

- If the exception has not been fully handled, then a new exception should be
  thrown which can be caught by a higher level CATCH. You can throw a new
  exception using the normal THROW, which will clear exception.Stack and any
  higher CATCH will have no awareness of the original exception.

  Alternatively, you may rethrow an exception and preserve the exeption stack
  all the way to the original exception:

    call exception rethrow  Code  Message  Location

  It is your choice as to whether you want to pass the original Code and/or
  Message and/or Location. Either way, the stack will preserve all exceptions
  if rethrow is used.

  Rethrow should only be used within a CATCH block.


One last restriction - the full path to EXCEPTION.BAT must not include ! or ^.


This documentation can be accessed via the following commands

    constant stream:   exception /?   OR  exception help
    paged via MORE:    exception /??  OR  exception pagedHelp

The version of this utility can be accessed via

    exception /v  OR  exception version


EXCEPTION.BAT was designed and written by Dave Benham, with important
contributions from DosTips users jeb and siberia-man.

Development history can be traced at:
  http://www.dostips.com/forum/viewtopic.php?f=3&t=6497

Ci-dessous est un script pour tester les capacités D'EXCEPTION.CHAUVE. Le script s'appelle récursivement 7 fois. Chaque itération a deux appels, l'un à a :label qui montre la propagation d'exception normale, et l'autre à a script qui montre la propagation des exceptions entre les appels de script.

En revenant d'un appel récursif, il lève une exception si le nombre d'itérations est un multiple de 3 (itérations 3 et 6).

Chaque appel a son propre gestionnaire d'exception qui signale normalement l'exception, puis repousse une exception modifiée. Mais si le nombre d'itérations est de 5, l'exception est gérée et le traitement normal reprend.

@echo off

:: Main
setlocal enableDelayedExpansion
if not defined @Try call exception init

set /a cnt+=1
echo Main Iteration %cnt% - Calling :Sub
%@Try%
(
  call :Sub
  call echo Main Iteration %cnt% - :Sub returned %%errorlevel%%
)
%@EndTry%
:@Catch
  setlocal enableDelayedExpansion
  echo(
  echo Main Iteration %cnt% - Exception detected:
  echo   Code     = !exception.code!
  echo   Message  = !exception.msg!
  echo   Location = !exception.loc!
  echo Rethrowing modified exception
  echo(
  endlocal
  call exception rethrow -%cnt% "Main Exception^!" "%~f0<%~0>"
:@EndCatch
echo Main Iteration %cnt% - Exit
exit /b %cnt%


:Sub
setlocal
echo :Sub Iteration %cnt% - Start
%@Try%
  if %cnt% lss 7 (
    echo :Sub Iteration %cnt% - Calling "%~f0"
    call "%~f0"
    %= Show any non-exception return code (demonstrate ERRORLEVEL is preserved if no exception) =%
    call echo :Sub Iteration %cnt% - testException returned %%errorlevel%%
  )
  %= Throw an exception if the iteration count is a multiple of 3 =%
  set /a "1/(cnt%%3)" 2>nul || (
    echo Throwing exception
    call exception throw -%cnt% "Divide by 0 exception^!" "%~f0<%~0>"
  )
%@EndTry%
:@Catch
  setlocal enableDelayedExpansion
  echo(
  echo :Sub Iteration %cnt% - Exception detected:
  echo   Code     = !exception.code!
  echo   Message  = !exception.msg!
  echo   Location = !exception.loc!
  endlocal
  %= Handle the exception if iteration count is a multiple of 5, else rethrow it with new properties =%
  set /a "1/(cnt%%5)" 2>nul && (
    echo Rethrowing modified exception
    echo(
    call exception rethrow -%cnt% ":Sub Exception^!" "%~f0<%~0>"
  ) || (
    call exception clear
    echo Exception handled
    echo(
  )
:@EndCatch
echo :Sub Iteration %cnt% - Exit
exit /b %cnt%

-- sortie --

Main Iteration 1 - Calling :Sub
:Sub Iteration 1 - Start
:Sub Iteration 1 - Calling "C:\test\testException.bat"
Main Iteration 2 - Calling :Sub
:Sub Iteration 2 - Start
:Sub Iteration 2 - Calling "C:\test\testException.bat"
Main Iteration 3 - Calling :Sub
:Sub Iteration 3 - Start
:Sub Iteration 3 - Calling "C:\test\testException.bat"
Main Iteration 4 - Calling :Sub
:Sub Iteration 4 - Start
:Sub Iteration 4 - Calling "C:\test\testException.bat"
Main Iteration 5 - Calling :Sub
:Sub Iteration 5 - Start
:Sub Iteration 5 - Calling "C:\test\testException.bat"
Main Iteration 6 - Calling :Sub
:Sub Iteration 6 - Start
:Sub Iteration 6 - Calling "C:\test\testException.bat"
Main Iteration 7 - Calling :Sub
:Sub Iteration 7 - Start
:Sub Iteration 7 - Exit
Main Iteration 7 - :Sub returned 7
Main Iteration 7 - Exit
:Sub Iteration 6 - testException returned 7
Throwing exception

:Sub Iteration 6 - Exception detected:
  Code     = -6
  Message  = Divide by 0 exception!
  Location = C:\test\testException.bat<:Sub>
Rethrowing modified exception


Main Iteration 6 - Exception detected:
  Code     = -6
  Message  = :Sub Exception!
  Location = C:\test\testException.bat<:Sub>
Rethrowing modified exception


:Sub Iteration 5 - Exception detected:
  Code     = -6
  Message  = Main Exception!
  Location = C:\test\testException.bat<C:\test\testException.bat>
Exception handled

:Sub Iteration 5 - Exit
Main Iteration 5 - :Sub returned 5
Main Iteration 5 - Exit
:Sub Iteration 4 - testException returned 5
:Sub Iteration 4 - Exit
Main Iteration 4 - :Sub returned 4
Main Iteration 4 - Exit
:Sub Iteration 3 - testException returned 4
Throwing exception

:Sub Iteration 3 - Exception detected:
  Code     = -3
  Message  = Divide by 0 exception!
  Location = C:\test\testException.bat<:Sub>
Rethrowing modified exception


Main Iteration 3 - Exception detected:
  Code     = -3
  Message  = :Sub Exception!
  Location = C:\test\testException.bat<:Sub>
Rethrowing modified exception


:Sub Iteration 2 - Exception detected:
  Code     = -3
  Message  = Main Exception!
  Location = C:\test\testException.bat<C:\test\testException.bat>
Rethrowing modified exception


Main Iteration 2 - Exception detected:
  Code     = -2
  Message  = :Sub Exception!
  Location = C:\test\testException.bat<:Sub>
Rethrowing modified exception


:Sub Iteration 1 - Exception detected:
  Code     = -2
  Message  = Main Exception!
  Location = C:\test\testException.bat<C:\test\testException.bat>
Rethrowing modified exception


Main Iteration 1 - Exception detected:
  Code     = -1
  Message  = :Sub Exception!
  Location = C:\test\testException.bat<:Sub>
Rethrowing modified exception


Unhandled batch exception:
  Code = -1
  Msg  = Main Exception!
  Loc  = C:\test\testException.bat<testException>
  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!]

Enfin, ici sont une série de scripts triviaux qui montrent comment les exceptions peuvent être utilisées efficacement même lorsque les scripts intermédiaires ne savent rien à leur sujet!

Commencez avec un utilitaire de script de division simple qui divise deux nombres et imprime le résultat:

Diviser.MTD

:: divide.bat  numerator  divisor
@echo off
setlocal
set /a result=%1 / %2 2>nul || call exception throw -100 "Division exception" "divide.bat"
echo %1 / %2 = %result%
exit /b

Notez comment le script lève une exception s'il détecte une erreur, mais il ne fait rien pour attraper l'exception.

Maintenant, je vais écrire un harnais de test de division qui est totalement naïf sur batch exception.

TestDivide.MTD

@echo off
for /l %%N in (4 -1 0) do call divide 12 %%N
echo Finished successfully!

-- sortie--

C:\test>testDivide
12 / 4 = 3
12 / 3 = 4
12 / 2 = 6
12 / 1 = 12

Unhandled batch exception:
  Code = -100
  Msg  = Division exception
  Loc  = divide.bat
  Stack= testDivide divide [-100:Division exception]

Notez comment L'écho final ne s'exécute jamais car l'exception soulevée par divide.chauve-souris n'a pas été gérée.

Enfin, je vais écrire un script maître qui appelle le testdivide naïf et gère correctement l'exception:

Maître.MTD

@echo off
setlocal
call exception init

%@Try%
  call testDivide
%@EndTry%
:@Catch
  echo %exception.Msg% detected and handled
  call exception clear
:@EndCatch
echo Finished Successfully!

-- sortie --

C:\test>master
12 / 4 = 3
12 / 3 = 4
12 / 2 = 6
12 / 1 = 12
Division exception detected and handled
Finished Successfully!

Le script maître a réussi à attraper une exception soulevée par divide.chauve, même si elle a dû passer par testDivide.bat, qui ne sait rien sur les exceptions. Très cool: -)

Maintenant, ce n'est certainement pas une panacée pour toutes les choses liées à la gestion des erreurs:

  • Il existe un certain nombre de limitations syntaxiques et de disposition de code qui sont entièrement décrites dans la documentation intégrée. Mais rien de trop flagrant.

  • Il n'y a aucun moyen de traiter automatiquement toutes les erreurs comme des exceptions. Toutes les exceptions doivent être explicitement levées par code. C'est probablement une bonne chose, étant donné que les rapports d'erreurs sont gérés par convention - il n'y a pas de règles strictes. Certains programmes ne suivent pas la convention. Par exemple, HELP ValidCommand renvoie ERRORLEVEL 1, qui implique par convention une erreur, tandis que HELP InvalidCommand renvoie ERRORLEVEL 0, ce qui implique un succès.

  • Cette technique d'exception de lot ne peut pas détecter et gérer les erreurs d'exécution fatales. Par exemple, GOTO :NonExistentLabel mettra toujours fin immédiatement à tout traitement par lots, sans possibilité d'attraper l'erreur.

Vous pouvez suivre le développement de L'EXCEPTION.MTD à http://www.dostips.com/forum/viewtopic.php?f=3&t=6497 . Tout développement futur y sera affiché. Je ne mettrai probablement pas à jour ce post StackOverflow.

27
répondu dbenham 2016-08-16 12:07:18

Eh bien, si le terme "gestion des exceptions" est pris dans le même sens que les autres langages de programmation, je pense que la réponse est: "non".

Dans tous les langages de programmation standard, le terme "gestion des exceptions" fait référence à "l'apparition, pendant le calcul, d'exceptions – conditions anormales ou exceptionnelles nécessitant un traitement spécial", comme les erreurs d'exécution qui peuvent être gérées d'une manière différente de la gestion des erreurs standard effectuée par le système.

Par exemple, en C++: "Les Exceptions sont des anomalies d'exécution, telles que la division par zéro, qui nécessitent une gestion immédiate lorsqu'elles sont rencontrées par votre programme".

Le. NET Framework spécifie: "les Exceptions représentent les erreurs qui se produisent lors de l'exécution de l'application".

Dans Visual Basic 6 : "Visual Basic prend en charge la gestion des exceptions (erreurs), ce qui permet au programme de détecter et éventuellement de récupérer des erreurs lors de l'exécution."

La description JScript indiquer: "Le coup d'essayer...attraper...enfin relevé fournit un moyen de gérer certaines ou de toutes les erreurs possibles qui peuvent se produire dans un bloc de code, pendant l'exécution de code".

Dans toutes ces langues, la" gestion des exceptions " signifie gérer une erreur d'exécution qui, autrement, entraînerait l'interruption du programme avec un message d'erreur. La façon de le faire est via le "essayer...catch " déclaration de cette façon:

try {
   *any* code 
   that may cause a *run-time ERROR*
}
catch (exception) {
   code that allows to *identify the error*
   testing specific values of "exception"
}

Maintenant, les différences par rapport au Code de fichier Batch proposé émulation.

Dans un fichier Batch, il n'y a aucun moyen de "gérer" une erreur d'exécution: toutes les erreurs d'exécution provoquent l'arrêt de l'exécution du fichier Batch avec un message d'erreur. Dans les fichiers Batch, d'une manière différente des autres langages, il y a plusieurs situations qui sont pas signalées comme des "erreurs", mais tout comme le résultat gérable d'une commande. Par exemple, si la commande find ne trouve pas la chaîne de recherche, elle renvoie un niveau d'erreur supérieur à zéro, et dans un chemin, si set /A commande produit une "erreur d'exécution" (comme la division par zéro), il renvoie à un niveau supérieur à zéro et l'exécution de continuer normalement. De cette façon, tout programme peut gérer toute situation d'erreur possible qui est signalée de cette façon via le code de lot standard, sans avoir besoin de "gestion des exceptions".

Dans la norme "essayer...catch" fonctionnalité, code, ce qui peut produire toute erreur d'exécution peut être placé dans la "essayer" avec aucun autre test; l'exception est automatiquement jeté par le système. L'erreur particulière qui a causé l'exception peut être identifiée via des tests individuels dans la partie" catch". L'émulation par lots proposée est entièrement différente. Dans ce cas, chaque situation d ' "erreur" particulière doit être inspectée individuellement dans la partie "try" afin de explicitement lancer l ' "exception" correspondante; la partie "catch" doit également traiter chacune des exceptions données.

Ce le mécanisme ressemble plus à une autre fonctionnalité de langages de programmation standard: le mécanisme de" gestion des événements " des langages comme C++qui est également pris en charge via les fonctions de gestion des exceptions Windows. Dans ce schéma, une exception/événement est explicitement soulevée via la fonction RaiseException, ce qui fait que le thread d'exécution saute à la fonction précédemment enregistrée via AddExceptionHandler.

S'il vous Plaît, ne me comprenez pas mal. Je pense que cette méthode est un outil précieux cela peut faciliter la gestion des "erreurs" dans le code Batch d'une manière simple et puissante. Cependant, je suis en désaccord avec le schéma proposé d'utiliser cette fonctionnalité via le " essayer...catch " construction de langages de programmation standard, qui donne la fausse impression qu'il est possible d'émuler le mécanisme de gestion des exceptions standard dans les fichiers Batch Windows afin d'attraper les erreurs d'exécution. À mon humble avis, la méthode deviendrait proche des normes si elle était basée sur la "RegisterExceptionHandler "et" RaiseException " schéma à la place...

2
répondu Aacini 2015-07-16 15:34:12

L'utilisation de la syntaxe successCmd && ( failingCmd & (call ) ) || ( excHandlingCmd ) est assez agréable pour beaucoup de cas et ne nécessite aucun fichier supplémentaire comme décrit ici: https://stackoverflow.com/a/17085933/1915920

(le mannequin (call ) est seulement pour le cas de la 2ème (dernier) cmd échoue)

0
répondu Andreas Dietrich 2017-09-21 20:04:21