Подтвердить что ты не робот

Поддерживает ли пакет обработки исключений Windows?

Поддерживает ли пакетное программирование Windows обработку исключений? Если нет, есть ли способ эффективно эмулировать обработку исключений в пакетных файлах?

Я хотел бы иметь возможность "выбросить исключение" в любом месте пакета script на любом уровне CALL и периодически набирать стек CALL, пока он не найдет активный "блок TRY", после чего "блок CATCH" "может полностью обрабатывать исключение и продолжать или выполнять некоторую очистку и продолжать использовать стек CALL. Если исключение никогда не обрабатывается, пакетная обработка прекращается, и управление возвращается в контекст командной строки с сообщением об ошибке.

Пара уже сообщила о способах прекращения пакетной обработки на любой глубине CALL, но ни одна из этих методик не позволяет любой структурированной деятельности по очистке, которая обычно предоставляется в других Языки с помощью обработки исключений.

Примечание: Это случай, когда я уже знаю хороший ответ, который был недавно обнаружен, и я хочу поделиться информацией

4b9b3361

Ответ 1

В сценариях для Windows, конечно же, нет формальной обработки исключений - вряд ли удивительно, учитывая, насколько примитивным является язык. Никогда в моих самых смелых мечтах я никогда не думал, что эффективная обработка исключений может быть взломана.

Но затем некоторые удивительные открытия были сделаны на российском сайте о поведении ошибочного заявления GOTO (я понятия не имею, что сказано, Я не могу читать по-русски). В DosTips было опубликовано английское резюме, и поведение было дополнительно исследовано.

Оказывается, что (GOTO) 2>NUL ведет себя почти идентично EXIT/B, , за исключением конкатенированных команд в уже обработанном блоке кода, все еще выполняется после эффективного возврата, в контексте CALLER!

Вот краткий пример, демонстрирующий большинство значимых точек.

@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

- OUTPUT -

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

Эта функция абсолютно неожиданна и невероятно мощна и полезна. Он используется для:

  • Создать PrintHere.bat - эмуляция функции документа 'nix здесь
  • Создайте утилиту RETURN.BAT, чтобы любая пакетная функция могла удобно вызвать любое значение через барьер ENDLOCAL, практически без ограничений, Код представляет собой флеш-версию оригинальной идеи jeb.

Теперь я также могу добавить обработку исключений в список: -)

Этот метод использует пакетную утилиту EXCEPTION.BAT для определения переменных среды "макросы", которые используются для указания блоков TRY/CATCH, а также для исключения исключений.

Прежде чем реализовать блок TRY/CATCH, макросы должны быть определены с помощью:

call exception init

Затем блоки TRY/CATCH определяются со следующим синтаксисом:

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

Исключения могут быть сброшены в любое время через:

call exception throw  errorNumber  "messageString"  "locationString"

Когда генерируется исключение, он выставляет стек CALL итеративно с помощью (GOTO) 2>NUL, пока не найдет активный TRY/CATCH, после чего он будет отнесен к блоку CATCH и выполнит этот код. Ряд переменных атрибута исключения доступен для блока CATCH:

  • exception.Code - числовой код исключения
  • exception.Msg - Строка сообщения исключения
  • exception.Loc - строка, описывающая местоположение, в котором было выбрано исключение
  • exception.Stack - строка, которая отслеживает стек вызовов из блока CATCH (или командной строки, если не поймана), вплоть до возникновения исключения.

Если исключение полностью обрабатывается, исключение должно быть очищено с помощью call exception clear, а script выполняется нормально. Если исключение не полностью обработано, то новое исключение может быть выбрано с использованием нового исключения. Stack или старый стек можно сохранить с помощью

call exception rethrow  errorNumber  "messageString"  "locationString"

Если исключение не обрабатывается, тогда печатается сообщение "необработанное исключение", включая четыре атрибута исключения, вся пакетная обработка завершается, а управление возвращается в контекст командной строки.

Вот код, который делает все это возможным: полная документация встроена в script и доступна из командной строки через exception help или exception /?.

EXCEPTION.BAT

::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

Ниже script, чтобы проверить возможности EXCEPTION.BAT. script рекурсивно называет себя 7 раз. Каждая итерация имеет два CALL, один для метки:, демонстрирующий нормальное распространение исключения, а другой - для script, который демонстрирует распространение исключений через script CALL.

При возврате из рекурсивного вызова он выдает исключение, если счетчик итераций кратен 3 (итерации 3 и 6).

Каждый CALL имеет свой собственный обработчик исключений, который обычно сообщает об исключении, а затем повторяет измененное исключение. Но если счетчик итераций равен 5, то обрабатывается исключение и возобновляется нормальная обработка.

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

- OUTPUT -

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!]

Наконец, вот серия тривиальных сценариев, которые показывают, как исключения могут эффективно использоваться, даже если промежуточные скрипты ничего не знают о них!

Начните с простой утилиты script, которая делит два числа и печатает результат:

divide.bat

:: 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

Обратите внимание, что script генерирует исключение, если оно обнаруживает ошибку, но ничего не делает для исключения.

Теперь я напишу тест-драйв с разделением, который абсолютно наивен в отношении исключений пакетов.

testDivide.bat

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

- ВЫВОД -

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]

Обратите внимание на то, как последний ECHO никогда не выполняется, потому что исключение, вызванное debide.bat, не обрабатывалось.

Наконец, я напишу мастер script, который вызывает наивный testDivide и правильно обрабатывает исключение:

master.bat

@echo off
setlocal
call exception init

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

- OUTPUT -

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

Мастер script смог успешно поймать исключение, созданное divide.bat, хотя он должен был пройти через testDivide.bat, который ничего не знает об исключениях. Очень круто: -)

Теперь это, конечно, не панацея для всех вещей, связанных с обработкой ошибок:

  • Существует ряд ограничений синтаксического и кодового макета, которые полностью описаны во встроенной документации. Но ничего слишком вопиющего.

  • Невозможно автоматически обрабатывать все ошибки как исключения. Все исключения должны быть явно заданы кодом. Вероятно, это хорошо, учитывая, что сообщение об ошибках обрабатывается по соглашению - нет строгих правил. Некоторые программы не соответствуют конвенции. Например, HELP ValidCommand возвращает ERRORLEVEL 1, который по соглашению подразумевает ошибку, а HELP InvalidCommand возвращает ERRORLEVEL 0, что подразумевает успех.

  • Этот метод исключения пакетов не может улавливать и обрабатывать фатальные ошибки времени выполнения. Например, GOTO :NonExistentLabel будет по-прежнему немедленно прекращать всю пакетную обработку, без какой-либо возможности поймать ошибку.

Вы можете следить за развитием EXCEPTION.BAT в http://www.dostips.com/forum/viewtopic.php?f=3&t=6497. Любые будущие разработки будут размещены там. Вероятно, я не буду обновлять этот пост StackOverflow.

Ответ 2

Хорошо, если термин "обработка исключений" принимается в том же смысле других языков программирования, я думаю, что ответ: "НЕТ".

Во всех стандартных языках программирования термин "обработка исключений" относится к "возникновение, при вычислении, исключений - аномальные или исключительные условия, требующие специальная обработка", такие как ошибки времени выполнения, которые могут управляться таким образом, который отличается от стандартной обработки ошибок, выполняемой системой.

Например, в С++: "Исключения - это аномалии во время выполнения, такие как деление на ноль, которые требуют немедленной обработки при столкновении с вашим программа".

.NET Framework указывают: "Исключения представляют ошибки, возникающие во время выполнения приложения".

В Visual Basic 6: "Visual Basic поддерживает обработку исключений (ошибок), что позволяет программе обнаруживать и, возможно, восстанавливать ошибки при выполнении."

Описание JScript указывает: "Инструкция try... catch... finally предоставляет способ обработки некоторых или всех возможных ошибки, которые могут возникать в данном блоке кода, в то время как все еще выполняется код".

Во всех этих языках обработка исключений означает управление ошибкой во время выполнения, которая в противном случае вызывала бы прерывание программы с сообщением об ошибке. Способ сделать это через инструкцию "try... catch" следующим образом:

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

Теперь отличия от предлагаемой эмуляции кода пакетного файла.

В пакетном файле нет возможности "управлять" ошибкой во время выполнения: все ошибки времени выполнения приводят к остановке выполнения командного файла с сообщением об ошибке. В пакетных файлах, отличных от других языков, существует несколько ситуаций, которые не сообщаются как "ошибки", а также как управляемый результат команды. Например, если команда find не может найти строку поиска, она возвращает уровень ошибок больше нуля и полностью эквивалентно, если команда set /A создает "ошибку времени выполнения" (например, деление на ноль) он возвращает уровень ошибок больше нуля, и выполнение продолжается нормально. Таким образом, любая программа может управлять любой возможной ситуацией с ошибкой, которая сообщается этим способом через стандартный пакетный код, без необходимости обработки исключений.

В стандартной функции "try... catch" любой код, который может вызвать любую ошибку времени выполнения, может быть помещен в часть "try" без дальнейшего тестирования; исключение автоматически выбрасывается системой. Конкретная ошибка, вызвавшая исключение, может быть идентифицирована с помощью отдельных тестов в разделе "catch". Предложенная эмуляция партии полностью отличается. В этом случае каждая конкретная ситуация "ошибки" должна быть индивидуально проверена в части "try", чтобы явно выбросить соответствующее "исключение"; часть "catch" также должна обрабатывать каждое из указанных исключений.

Этот механизм больше похож на еще одну функцию стандартных языков программирования: механизм управления событиями языков как и С++, который также поддерживается через Функции обработки исключений Windows. В этой схеме исключение/событие явно выражается функцией RaiseException, что приводит к тому, что поток выполнения переходит к функции, ранее зарегистрированной через AddExceptionHandler.

Пожалуйста, не поймите меня неправильно. Я думаю, что этот метод является ценным инструментом, который может облегчить управление "ошибками" в пакетном коде простым и мощным способом. Однако я не согласен с предлагаемой схемой использования этой функции с помощью конструкции "try... catch" стандартных языков программирования, которая дает ложное впечатление, что можно эмулировать стандартный механизм обработки исключений в файлах Windows Batch, чтобы поймать ошибки времени выполнения. По моему скромному мнению, метод приблизится к стандартам, если он будет основан на схеме "RegisterExceptionHandler" и "RaiseException"...

Ответ 3

используя синтаксис successCmd && ( failingCmd & (call ) ) || ( excHandlingCmd ), довольно хорош для многих случаев и не требует дополнительных файлов, также описанных здесь: fooobar.com/info/109202/...

(фиктивный (call ) относится только к случаю, когда 2-й (последний) cmd не работает)