Toplu iş dosyasından altyordamdan çık


20

Bir alt programın içinden bir toplu iş dosyasından nasıl çıkabilirim?

EXIT komutunu kullanırsam, alt rutini çağırdığım satıra dönüp yürütme devam eder.

İşte bir örnek:

@echo off
ECHO Quitting...
CALL :QUIT
ECHO Still here!
GOTO END

:QUIT
EXIT /B 1

:END
EXIT /B 0

Çıktı:

Quitting...
Still here!

Güncelleme:

Bu doğru bir cevap değil, ama sonunda şu şeyleri yaptım:

@echo off
CALL :SUBROUTINE_WITH_ERROR || GOTO HANDLE_FAIL
ECHO You shouldn't see this!
GOTO END

:SUBROUTINE_WITH_ERROR
ECHO Simulating failure...
EXIT /B 1

:HANDLE_FAIL
ECHO FAILURE!
EXIT /B 1

:END
ECHO NORMAL EXIT!
EXIT /B 0

Çift borulu ifadesi:

CALL :SUBROUTINE_WITH_ERROR || GOTO HANDLE_FAIL

kısaltması:

CALL :SUBROUTINE_WITH_ERROR 
IF ERRORLEVEL 1 GOTO HANDLE_FAIL    

Hâlâ CALLER'in durumu ele alması yerine doğrudan bir altyordamdan çıkmanın bir yolu olup olmadığını bilmek isterim, ancak bu en azından işi hallediyor.


Güncelleme # 2: Yukarıdaki şekilde çağrılan başka bir altyordam içinden bir altyordam çağırırken, böylelikle altyordamlar içinden çağırıyorum:

CALL :SUBROUTINE_WITH_ERROR || EXIT /B 1

Bu şekilde, hata, "ana" ye kadar yayılır. Toplu işin ana kısmı hatayı hata işleyicisi GOTO: FAILURE ile işleyebilir

Yanıtlar:


21

Bunu toplu iş dosyanızın üstüne ekleyin:

@ECHO OFF
SETLOCAL

IF "%selfWrapped%"=="" (
  REM this is necessary so that we can use "exit" to terminate the batch file,
  REM and all subroutines, but not the original cmd.exe
  SET selfWrapped=true
  %ComSpec% /s /c ""%~0" %*"
  GOTO :EOF
)

Ardından şunları arayabilirsiniz:

  • EXIT [errorLevel] tüm dosyadan çıkmak istiyorsanız
  • EXIT /B [errorLevel] geçerli altyordamdan çıkmak için
  • GOTO :EOF geçerli altyordamdan çıkmak için

Aslında bahsetmek için +1GOTO :EOF
afrazier

1
Çok hoş. Ben atamak küçük bir değişiklik yapılmasını, yaptık %~0değişkeni yerine true: if not "%selfwrapped%"=="%~0" ( set selfwrapped=%~0 .... ). Bu şekilde, aynı numarayı birbirini çağıran birden çok toplu komut dosyasında kullanabilirsiniz.
GolezTrol

Bu harika bir çözüm. Nasıl çalıştığını açıklamanın bir düzenlemeye değer olduğunu düşünüyor musunuz? Bunların hepsini açmam ve bir toplu iş dosyasını ( %~0) %*iç içe cmd.exe'den tüm argümanlarla ( ) çağırdığını fark etmem bir dakikamı aldı /sve %ComSpec%argümanın, çift tırnak işaretlerini işleme şeklini kontrol etmek için kullanılır . aramak.
Sean

@Sean kısalığı çoğu insan için daha yararlı buluyorum. Yazdığımdan bu yana 7 yıl içinde daha fazla belge istenmemişti, bu yüzden yüksek talep görmüyor gibi görünüyor. Ayrıca, kendilerine bir şeyler arayan ve dokümanları kopyalamak / parçalamak yerine insanların bir değeri olduğunu düşünüyorum. Ama belki birkaç kişi daha sorarsa bir şeyler ekleyebilirim. Aynı zamanda bir CW yani siz de bir düzenleme önerebilirsiniz
Merlyn Morgan-Graham

3

Bu küçük ayarlamaya ne dersiniz?

@echo off
ECHO Quitting...
CALL :QUIT
:: The QUIT subroutine might have set the error code so let's take a look.
IF ERRORLEVEL 1 GOTO :EOF
ECHO Still here!
GOTO END

:QUIT
EXIT /B 1

:END
EXIT /B 0

Çıktı:

Quitting...

Teknik olarak bu, altyordam içinden çıkmaz. Aksine, altyordamın sonucunu kontrol eder ve oradan harekete geçer.


2
Teşekkürler, bu kesinlikle işi halledecektir ve daha iyi bir cevap bulamazsam, yapmam gerekecek şey budur. Ancak, bu satırı uzun ve karmaşık toplu iş dosyamdaki her CALL'dan sonra yapıştırmak istemem.
Brown

1

Yordamdan geri dönmek istemiyorsanız kullanmayın call: kullanın goto.

@echo off
ECHO Quitting...
GOTO :QUIT
ECHO Will never be there!
GOTO END

:QUIT
EXIT /B 1

:END
EXIT /B 0

Sorunun amacı, alt programlardan nasıl yapılacağıdır (yani çağrıyı kullanarak), bu yüzden cevap vermez.
Steve Crane

1

Toplu iş dosyalarıma hata işleme koydum. Bunun gibi hata işleyicilerini arayabilirsiniz:

CALL :WARNING "This is" "an important" "warning."

Ve işte toplu iş dosyasının sonu:

::-------------------------------------------------------------------
::  Decisions
::-------------------------------------------------------------------
:INFO
IF "_DEBUG"=="true" (
  ECHO INFO: %~1
  IF NOT "%~2"=="" ECHO          %~2
  IF NOT "%~3"=="" ECHO          %~3
)
EXIT /B 0
:WARNING
ECHO WARNING: %~1
IF NOT "%~2"=="" ECHO          %~2
IF NOT "%~3"=="" ECHO          %~3
EXIT /B 0
:FAILURE
ECHO FAILURE: %~1
IF NOT "%~2"=="" ECHO          %~2
IF NOT "%~3"=="" ECHO          %~3
pause>nul
:END
ECHO Closing Server.bat script
FOR /l %%a in (5,-1,1) do (TITLE %TITLETEXT% -- closing in %%as&PING.exe -n 2 -w 1 127.0.0.1>nul)

1

Bu, geçerli bağlamdan ve bir üst bağlamdan çıkar (yani, bir callderin altyordam betiğinin içinde yürütüldüğünde çıkacaktır):

(goto) 2>nul || exit /b

Veya, hata seviyesi 0'a ihtiyacınız varsa:

(goto) 2>nul || (
    type nul>nul
    exit /b
)

Temel olarak, (goto) 2>nulhata seviyesini 1 olarak ayarlar (hata çıkmadan), üst bağlamda çift boru yürütüldükten sonra yürütmeyi üst bağlama ve koda döndürür. type nul>nulhata seviyesini 0 olarak ayarlar.

UPD:

Yürütmeyi art arda iki kereden fazla geri döndürmek için, birkaçını şöyle zincirleyin (goto) 2>nul ||:

(goto) 2>nul || (goto) 2>nul || (goto) 2>nul || (
    type nul>nul
    exit /b
)

Bağlamı değişken sayıda döndürmek için özyinelemeli bir alt yordam şunlardır:

:Kill
(goto) 2>nul || (
    set /a depth=%1-1
    if %1 GEQ 1 (
        call:Kill !depth!
    )
    (goto) 2>nul || (type nul>nul)
)

Özyinelemeli bir işlevden çağrıldığında:

@echo off
setlocal EnableDelayedExpansion
call:Recurs 5
echo This won't be printed
exit /b

:Recurs
set /a ri+=1
echo %ri%
if %ri% LSS %1 (
    call:Recurs %1
)
echo This will be printed only once
call:Kill %1
exit /b

çıktı:

1
2
3
4
5
This will be printed only once
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.