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.