Keluar dari file batch dari subrutin


20

Bagaimana saya bisa keluar dari file batch dari dalam subrutin?

Jika saya menggunakan perintah EXIT, saya cukup kembali ke baris tempat saya memanggil subrutin, dan eksekusi berlanjut.

Ini sebuah contoh:

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

:QUIT
EXIT /B 1

:END
EXIT /B 0

Keluaran:

Quitting...
Still here!

Memperbarui:

Ini bukan jawaban yang tepat, tetapi saya akhirnya melakukan sesuatu seperti:

@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

Pernyataan pipa ganda:

CALL :SUBROUTINE_WITH_ERROR || GOTO HANDLE_FAIL

adalah singkatan untuk:

CALL :SUBROUTINE_WITH_ERROR 
IF ERRORLEVEL 1 GOTO HANDLE_FAIL    

Saya masih ingin tahu apakah ada cara untuk keluar langsung dari subrutin daripada harus membuat Penelepon menangani situasi, tetapi ini setidaknya menyelesaikan pekerjaan.


Pembaruan # 2: Ketika memanggil subrutin dari dalam subrutin lain, dipanggil dengan cara di atas, saya menelepon dari dalam subrutin berikut:

CALL :SUBROUTINE_WITH_ERROR || EXIT /B 1

Dengan cara ini, kesalahan menyebar kembali ke "utama", sehingga untuk berbicara. Bagian utama dari batch kemudian dapat menangani kesalahan dengan penangan kesalahan GOTO: FAILURE

Jawaban:


21

Tambahkan ini ke bagian atas file kumpulan Anda:

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

Maka Anda cukup menelepon:

  • EXIT [errorLevel] jika Anda ingin keluar dari seluruh file
  • EXIT /B [errorLevel] untuk keluar dari subrutin saat ini
  • GOTO :EOF untuk keluar dari subrutin saat ini

+1 untuk benar-benar disebutkanGOTO :EOF
afrika

1
Sangat bagus. Aku sudah membuat modifikasi kecil, menetapkan %~0ke variabel bukan true: if not "%selfwrapped%"=="%~0" ( set selfwrapped=%~0 .... ). Dengan cara itu Anda dapat menggunakan trik yang sama dalam beberapa skrip batch yang saling memanggil.
GolezTrol

Ini solusi hebat. Apakah menurut Anda layak diedit untuk menjelaskan cara kerjanya? Butuh waktu satu menit untuk membongkar semua itu dan menyadari itu sebenarnya hanya memanggil file batch ( %~0) dengan semua argumen ( %*) dari cmd.exe bersarang, dan /sdigunakan untuk mengontrol cara %ComSpec%argumen menangani tanda kutip ganda di sekitar panggilan.
Sean

@Sean Saya menemukan keringkasan lebih berguna bagi kebanyakan orang. Lebih banyak dokumen belum diminta dalam 7 tahun sejak saya menulisnya, jadi sepertinya tidak banyak diminati. Saya juga berpikir ada beberapa nilai bagi orang-orang mencari hal-hal sendiri dan tidak menipu / memecah dokumen. Tetapi mungkin jika beberapa orang bertanya saya bisa menambahkan sesuatu. Ini juga CW sehingga Anda dapat mengusulkan suntingan juga
Merlyn Morgan-Graham

3

Bagaimana dengan penyesuaian kecil ini?

@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

Keluaran:

Quitting...

Secara teknis ini tidak keluar dari dalam subrutin. Sebaliknya, ia hanya memeriksa hasil subrutin dan mengambil tindakan dari sana.


2
Terima kasih, itu pasti akan menyelesaikan pekerjaan, dan jika saya tidak dapat menemukan jawaban yang lebih baik itulah yang harus saya lakukan. Namun, saya lebih suka tidak harus menempelkan baris itu setelah setiap PANGGILAN dalam file batch saya yang panjang dan kompleks.
Brown

1

Jika Anda tidak ingin kembali dari prosedur, jangan gunakan call: alih-alih gunakan goto.

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

:QUIT
EXIT /B 1

:END
EXIT /B 0

Inti dari pertanyaan adalah bagaimana melakukannya dari subrutin (yaitu menggunakan panggilan) sehingga ini tidak menjawabnya.
Steve Crane

1

Saya menempatkan penanganan kesalahan dalam file batch saya. Anda dapat memanggil penangan kesalahan seperti ini:

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

Dan inilah akhir dari file batch:

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

Ini akan keluar dari konteks saat ini dan konteks induk (yaitu, ketika dieksekusi di dalam satu callskrip subrutin mendalam akan keluar):

(goto) 2>nul || exit /b

Atau, jika Anda membutuhkan tingkat kesalahan 0:

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

Pada dasarnya, (goto) 2>nulsetel tingkat kesalahan ke 1 (tanpa menghasilkan kesalahan), mengembalikan eksekusi ke konteks induk dan kode setelah pipa ganda dieksekusi dalam konteks induk. type nul>nulsetel tingkat kesalahan ke 0.

UPD:

Untuk mengembalikan eksekusi lebih dari dua kali berturut-turut, rantai beberapa (goto) 2>nul ||seperti ini:

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

Berikut ini adalah subrutin rekursif untuk mengembalikan konteks beberapa kali:

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

Ketika dipanggil dari fungsi rekursif:

@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

hasilnya adalah:

1
2
3
4
5
This will be printed only once
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.