Soru Windows toplu istisna desteği mi kullanıyor?


Windows toplu programlama desteği istisna işleme mi? Değilse, toplu iş dosyaları içinde istisna işlemlerini etkili bir şekilde taklit etmenin herhangi bir yolu var mı?

Bir toplu iş komut dosyası içinde herhangi bir ÇAĞRI düzeyinde "bir istisna atabilmeyi" ve CALL yığınının etkin bir "YTL bloğu" bulana kadar tekrar tekrar atılmasını istiyorum, bunun üzerine bir "CATCH bloğu" istisnayı kaldırabilir Tamamen ve devam edin, ya da bazı temizlik yapın ve ÇAĞRI yığınını haşhaş etmeye devam edin. İstisna hiçbir zaman ele alınmazsa, toplu işlem sonlandırılır ve kontrol bir hata mesajıyla komut satırı bağlamına döner.

Zaten var çift, herhangi bir ÇAĞRI derinliğinde toplu işlemeyi sonlandırmak için yollar gönderdiAncak, bu tekniklerin hiçbiri, istisna işleme yoluyla normal olarak diğer dillerde sağlanacak yapılandırılmış bir temizleme aktivitesine izin vermez.

Not:  Bu, yakın zamanda keşfedilen iyi bir cevabı zaten bildiğim bir durumdur ve bilgileri paylaşmak istiyorum.


21
2017-07-16 04:24


Menşei




Cevaplar:


Windows parti betikleme kesinlikle herhangi bir resmi istisna işleme sahip değildir - dilin ne kadar ilkel olduğunu göz önünde bulundurmak hiç de şaşırtıcı değildir. En vahşi rüyalarımda hiçbir zaman etkili istisna işleminin hacklenebileceğini düşünmemiştim.

Ama sonra bazı inanılmaz keşifler yapıldı. Rus sitesi hatalı bir GOTO bildirisinin davranışlarıyla ilgili (ne söylendiğine dair hiçbir fikrim yok, Rusça okuyamıyorum). DosTips'te bir İngilizce özet yayınlandıve davranış daha fazla araştırıldı.

Şekline dönüştü (GOTO) 2>NUL neredeyse EXIT / B'ye benzer davranır, zaten ayrıştırılmış bir kod bloğu içinde birleştirilmiş komutlar hariç, etkili geri dönüşten sonra hala yürütülür.  CALLer bağlamında!

İşte göze çarpan noktaların çoğunu gösteren kısa bir örnek.

@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

-- ÇIKTI --

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

Bu özellik tamamen beklenmedik ve inanılmaz derecede güçlü ve kullanışlı. Şunlar için kullanılmıştır:

  • yaratmak PrintHere.bat - burada 'nix'in belge özelliği öykünmesi
  • Oluşturmak RETURN.BAT yardımcı programı herhangi bir parti "fonksiyonu", ENDLOCAL bariyeri boyunca herhangi bir değeri hemen hemen hiç bir sınırlama olmaksızın döndürmek için ÇAĞRI YAPABİLİR. Kod bir etli çıkışlı sürümüdür jeb'in orijinal fikri.

Şimdi de listeye istisna işleme ekleyebilirim :-)

Teknik, EXCEPTION.BAT adlı bir toplu iş aracına dayanarak, TL / CATCH bloklarını belirtmek için kullanılan ortam değişkenlerini "makroları" tanımlamak ve istisnalar atmak için kullanılır.

Bir TL / CATCH bloğu uygulanmadan önce makrolar aşağıdakiler kullanılarak tanımlanmalıdır:

call exception init

Daha sonra TRY / CATCH blokları aşağıdaki sözdizimi ile tanımlanır:

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

İstisnalar şu adresten herhangi bir zamanda atılabilir:

call exception throw  errorNumber  "messageString"  "locationString"

Bir özel durum atıldığında, CALL yığını yinelemeli olarak kullanarak açılır. (GOTO) 2>NUL aktif bir TL / CATCH bulana kadar, CATCH bloğuna geçer ve bu kodu uygular. CATCH bloğu için bir dizi istisna özniteliği var:

  • exception.Code - Sayısal istisna kodu
  • exception.Msg - İstisna mesaj dizesi
  • exception.Loc - İstisnanın atıldığı yeri açıklayan dizgi
  • exception.Stack - İstisna orijinine kadar CATCH bloğundan (veya yakalanmadığı takdirde komut satırından) çağrı yığınını izleyen bir dize.

İstisna tamamen ele alınırsa istisna, call exception clearve betik normal olarak devam eder. İstisna tam olarak ele alınmazsa, yepyeni bir istisna ile yeni bir istisna atılabilir.Stack veya eski yığın korunabilir

call exception rethrow  errorNumber  "messageString"  "locationString"

Bir özel durum ele alınmazsa, dört istisna özniteliği de dahil olmak üzere "işlenmemiş özel durum" iletisi yazdırılır, tüm toplu işlem sonlandırılır ve denetim komut satırı içeriğine döndürülür.

Tüm bunları mümkün kılan kod - tam dokümantasyon komut dosyası içine gömülür ve komut satırından exception help veya 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

Aşağıda EXCEPTION.BAT yeteneklerini test etmek için betik. Komut, özyinelemeli olarak 7 kez çağırır. Her yinelemede, normal istisna yayılımını gösteren bir diğerine iki CALL vardır: diğeri ise komut CALL'lerinde istisna yayılımını gösteren bir komut dosyasıdır.

Yinelemeli bir çağrıda dönerken, yineleme sayısı 3'ün bir katıysa (yineleme 3 ve 6) bir istisna atar.

Her ÇAĞRI, normal olarak istisna bildiren ve ardından değiştirilmiş bir özel durumu yeniden işleyen kendi özel durum işleyicisine sahiptir. Ancak yineleme sayısı 5 ise, istisna işlenir ve normal işleme devam eder.

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

-- ÇIKTI --

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

Son olarak, ara komut dosyalarının kendileri hakkında hiçbir şey bilmediği durumlarda bile istisnaların nasıl etkili bir şekilde kullanılabileceğini gösteren bir dizi önemsiz betik!

İki sayıyı bölen ve sonucu yazdıran basit bir bölüm komut dosyası yardımcı programı ile başlayın:

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

Bir hata algıladığında komut dosyasının nasıl bir istisna oluşturduğunu unutmayın, ancak bu özel durumu yakalamak için hiçbir şey yapmaz.

Şimdi toplu istisnalar hakkında tamamen naif olan bir bölünme testi demeti yazacağım.

testDivide.bat

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

--ÇIKTI--

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]

Divide.bat tarafından kaldırılan istisna, ele alınmadığı için, son ECHO'nun nasıl bir şekilde yürütüldüğünü unutmayın.

Sonunda naif testDivide çağırır ve istisna düzgün bir şekilde işleyen bir ana komut dosyası yazacağım:

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!

-- ÇIKTI --

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

Ana betik, istisnalar hakkında hiçbir şey bilmeyen testDivide.bat üzerinden geçmesine rağmen divide.bat tarafından oluşturulan bir istisnayı başarılı bir şekilde yakalayabilmiştir. Çok havalı :-)

Şimdi bu kesinlikle hata işleme ile ilgili her şey için bir açlık değil:

  • Yerleşik belgelerinde tam olarak açıklanan bir dizi sözdizimsel ve kod düzeni sınırlaması vardır. Ama hiçbir şey çok alçakgönüllü.

  • Tüm hataları bir istisna olarak otomatik olarak ele almanın bir yolu yoktur. Tüm istisnalar kod tarafından açıkça atılmalıdır. Bu hata raporlama kongre tarafından ele alındığı sürece, bu iyi bir şeydir - katı kurallar yoktur. Bazı programlar konvansiyonu takip etmez. Örneğin, HELP ValidCommandkural gereği bir hataya işaret eden ERRORLEVEL 1 değerini döndürür HELP InvalidCommand Başarı anlamına gelen ERRORLEVEL 0 değerini döndürür.

  • Bu toplu istisna tekniği, ölümcül çalıştırma zamanı hatalarını yakalayamaz ve işleyemez. Örneğin GOTO :NonExistentLabel hatayı yakalamak için herhangi bir fırsat olmadan, tüm toplu işleme hemen sonlandırır.

EXCEPTION.BAT'ın gelişimini takip edebilirsiniz. http://www.dostips.com/forum/viewtopic.php?f=3&t=6497. Gelecekteki gelişmeler burada yayınlanacak. Muhtemelen bu StackOverflow gönderisini güncellemem.


26
2017-07-16 04:28



İçimdeki dil nerd gerçekten etkilendi ve biraz heyecanlandı. Ama içimdeki bakım programcısı, toplu dosyaları arcane ve anlaşılmaz hale getirmenin bir başka yolunu daha çok şaşırtıyor. - Ryan Bemrose


Eh, "istisna işleme" terimi, diğer programlama dilleri aynı anlamda alınırsa, ben cevabın "HAYIR" olduğunu düşünüyorum.

Tüm standart programlama dillerinde "istisna işleme" terimi ifade eder sistem tarafından gerçekleştirilen standart hata işleminden farklı bir şekilde yönetilebilen çalışma zamanı hataları gibi "özel durumların hesaplanması sırasında, özel durum gerektiren anormal veya istisnai durumlar".

Örneğin, C ++ 'da: "İstisnalar, sıfıra bölünme gibi, programınız tarafından karşılaşıldığında hemen işlem yapılması gereken çalışma zamanı anomalileridir".

.NET Framework note: "İstisnalar uygulama yürütme sırasında oluşan hataları temsil eder".

İçinde Visual Basic 6: "Visual Basic, programın algılanması ve yürütme sırasında hatalardan kurtarılmasını sağlayan özel durum (hata) işlemeyi destekler."

JScript description: "try ... catch ... son cümlesi, hala kod çalıştırırken, belirli bir kod bloğunda oluşabilecek olası hataların bir kısmını veya tümünü işlemek için bir yol sağlar".

Bütün bu dillerde "istisna işleme", bir çalışma hatası Aksi takdirde programın bir hata mesajı ile kesintiye neden olur. Bunu yapmanın yolu "try ... catch" ifadesiyle şu şekilde:

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

Şimdi farkları toplu olarak önerilen Batch dosya kodu emülasyonu.

Batch dosyasında var asla Çalışma zamanı hatası "yönetmek" için: tüm çalışma zamanı hataları, Batch dosyasının bir hata iletisiyle yürütülmesini durdurmasına neden olur. Toplu iş dosyalarında, diğer dillerden farklı bir şekilde, birkaç durum vardır. değil "hatalar" olarak rapor edildi, ancak bir komutun yönetilebilir sonucu olarak. Örneğin, find komut arama dizesini bulamıyor, sıfırdan büyük bir errorlevel döndürüyor ve tamamen eşdeğer bir şekilde, Eğer set /A komut, "çalışma zamanı hatası" üretir (sıfıra bölünme gibi), sıfırdan büyük bir hata düzeyi döndürür ve yürütme normal devam ediyor. Bu şekilde, herhangi bir program, standart istisna koduyla "istisna işleme" gerekmeden bu şekilde raporlanan olası hata durumlarını yönetebilir.

Standart "try ... catch" özelliğinde, herhangi bir kod üretebilir herhangi bir çalışma zamanı hatasıdaha fazla test yapılmadan "deneyin" bölümüne yerleştirilebilir; istisna otomatik olarak atılır sistem tarafından. Özel duruma neden olan özel hata, "yakalama" bölümündeki bireysel testler aracılığıyla tanımlanabilir. Önerilen Toplu Öykünme tamamen farklıdır. Bu durumda, her bir "hata" durumu ayrı ayrı denetlenmelidir. "deneyin" bölümünde amacıyla açıkça karşılık gelen "istisna" atmak; "catch" bölümü de verilen istisnaların her birini işlemelidir.

Bu mekanizma, başka bir standart programlama dilleri özelliğine daha çok benziyor: dillerin "olay yönetimi" mekanizması C ++ gibi bu da üzerinden desteklenir Windows Özel Durum İşleme İşlevleri. Bu şemada bir istisna / olay açıkça yükseltilmiş RaiseException işleviyle, yürütme iş parçacığının AddExceptionHandler aracılığıyla daha önce kaydedilen işleve sıçramasına neden olur.

Beni yanlış anlama lütfen. Bu yöntemin, Batch kodundaki "hataların" yönetimini basit ve güçlü bir şekilde kolaylaştıracak değerli bir araç olduğunu düşünüyorum. Bununla birlikte, standart programlama dillerinin "try ... catch" yapısını kullanarak bu özelliği kullanmanın önerilen şemasına katılmıyorum. Bu, yakalama amacıyla Windows Batch dosyalarındaki standart istisna işleme mekanizmasını taklit etmek için yanlış bir izlenim bırakıyor. çalışma zamanı hataları. Benim düşünceme göre, yöntem "RegisterExceptionHandler" ve "RaiseException" şemasına dayalı olacaksa standartlara yakın olacaktı ...


2
2017-07-16 08:52





kullanmak successCmd && ( failingCmd & (call ) ) || ( excHandlingCmd ) sözdizimi, bir çok durumda oldukça iyidir ve ayrıca burada açıklandığı gibi herhangi bir ek dosya gerektirmez: https://stackoverflow.com/a/17085933/1915920

(manken (call ) sadece 2 (son) cmd başarısız olduğu durumda)


0
2017-09-21 13:23



Bu kodda bir hata var - olmalı (call ) herhangi bir hatayı temizler, (call) bu bir hatayı ayarlar. Ayrıca ilk grup seti yanlış yerleştirilmiş. Ancak, sabit olsa bile, bu, orijinal sorudaki hedefleri ele almaz. - dbenham
@dbenham: çok teşekkürler, düzeltildi. Kesinlikle tam bir istisna işleme tekniği değildir, ancak bunu basit bir şekilde nasıl mümkün olduğunu gösterir. Bunun için ilk Google hit olarak tökezledim bat handle error. Bunun dışında karmaşık exc düşünüyorum. Toplu dosyalarda işlem yapmaktan kaçınılmalıdır, çünkü zaten daha karmaşık tekniklerin, daha iyi betimleme ortamlarında (bash / cygwin, groovy, python, javascript / nodejs vb.) mevcut olacağını belirtmiştir. Eğer bu kadar uzaksa, kesmek yerine dili değiştirmeyi düşünmelidir. - Andreas Dietrich
Hala doğru değil. Sizin (call ) sadece ne zaman çalışır failingCmd başarılı, ama gerçekten her zaman sonra yürütmek istiyorsun failingCmdhata olmaması için Onu düzelteceğim. - dbenham
Tamam, şimdi düzeltildi, ancak bu cevap uygun değil. Referans ettiğin cevabı yazdığım için, bu tekniğin farkındaydım. - dbenham