Questão Sair do arquivo em lotes da sub-rotina


Como posso sair de um arquivo de lote de dentro de uma sub-rotina?

Se eu usar o comando EXIT, simplesmente retornarei à linha onde chamei a sub-rotina e a execução continuará.

Aqui está um exemplo:

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

:QUIT
EXIT /B 1

:END
EXIT /B 0

Saída:

Quitting...
Still here!

Atualizar:

Esta não é uma resposta adequada, mas acabei fazendo algo nos moldes de:

@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

A declaração double-pipe de:

CALL :SUBROUTINE_WITH_ERROR || GOTO HANDLE_FAIL

é uma abreviação para:

CALL :SUBROUTINE_WITH_ERROR 
IF ERRORLEVEL 1 GOTO HANDLE_FAIL    

Eu ainda adoraria saber se há uma maneira de sair diretamente de uma sub-rotina do que ter que fazer o CHAMADOR lidar com a situação, mas isso pelo menos faz o trabalho.


Atualização 2: Ao chamar uma sub-rotina de outra sub-rotina, chamada da maneira acima, eu chamo de dentro das sub-rotinas assim:

CALL :SUBROUTINE_WITH_ERROR || EXIT /B 1

Desta forma, o erro se propaga de volta para o "main", por assim dizer. A parte principal do lote pode manipular o erro com o manipulador de erros GOTO: FAILURE


17


origem




Respostas:


Adicione isto ao topo do seu arquivo de lote:

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

Então você pode simplesmente ligar:

  • EXIT [errorLevel] se você quiser sair do arquivo inteiro
  • EXIT /B [errorLevel] para sair da sub-rotina atual
  • GOTO :EOF para sair da sub-rotina atual

21



+1 para realmente mencionar GOTO :EOF - afrazier
Muito agradável. Eu fiz uma pequena modificação, atribuir %~0 para a variável em vez de true: if not "%selfwrapped%"=="%~0" ( set selfwrapped=%~0 .... ). Dessa forma, você pode usar o mesmo truque em vários scripts em lote que chamam uns aos outros. - GolezTrol
Esta é uma otima soluçao. Você acha que vale a pena editar para explicar como funciona? Levei um minuto para descompactar tudo isso e perceber que na verdade é só chamar o arquivo de lote (%~0) com todos os argumentos (%*) a partir de um cmd.exe aninhado e /s é usado para controlar a maneira como o %ComSpec% argumento manipula as aspas duplas em torno da chamada. - Sean
@Sean Acho que a brevidade é mais útil para a maioria das pessoas. Mais documentos não foram solicitados nos 7 anos desde que eu escrevi, então não parece estar em alta demanda. Eu também acho que há algum valor para as pessoas que procuram as coisas por si mesmas e não enganam / fragmentam os documentos. Mas talvez se mais algumas pessoas perguntarem que eu poderia acrescentar algo. É também uma CW, então você poderia propor uma edição também - Merlyn Morgan-Graham


Que tal esse pequeno ajuste?

@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

Saída:

Quitting...

Tecnicamente, isso não sai de dentro da sub-rotina. Em vez disso, ele simplesmente verifica o resultado da sub-rotina e toma ações a partir daí.


3



Obrigado, isso certamente faria o trabalho, e se eu não conseguir encontrar uma resposta melhor, é o que terei que fazer. No entanto, eu prefiro não ter que colar essa linha depois de cada chamada no meu arquivo de lote longo e complexo. - Brown


Se você não quiser voltar do procedimento, não use call: em vez disso, use goto.

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

:QUIT
EXIT /B 1

:END
EXIT /B 0

1



O ponto da questão é como fazê-lo a partir de sub-rotinas (ou seja, usando chamada) para que isso não responda. - Steve Crane


Eu coloquei o tratamento de erros nos meus arquivos em lote. Você pode chamar manipuladores de erro como este:

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

E aqui está o final do arquivo de lote:

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