2012-05-10 16 views
8

Tengo una función sencilla escrita para comprobar si hay directorios:¿Cómo puedo salir de un archivo por lotes desde una función?

:direxist 
if not exist %~1 (
    echo %~1 could not be found, check to make sure your location is correct. 
    goto:end 
    ) else (
    echo %~1 is a real directory 
    goto:eof 
    ) 

: fin se escribe como

:end 
endlocal 

No entiendo por qué el programa no se detendría después de Goto: fin se ha llamado . Tengo otra función que usa el mismo método para detener el programa y funciona bien.

:PRINT_USAGE 
echo Usage: 
echo ------ 
echo <file usage information> 
goto:end 

En este caso, el programa se detiene después de llamar a: end; ¿Por qué esto no funcionaría en: direxist? ¡Gracias por tu ayuda!

+0

posible duplicado de [escritura de la hornada salida desde el interior de una función] (http://stackoverflow.com/questions/3227796/exit-batch-script- from-inside-a-function) – Nathan

Respuesta

12

Supongo que está mezclando call y goto declaraciones aquí.

Una etiqueta en un archivo de proceso por lotes se puede utilizar con call o goto, pero el comportamiento es diferente.
Si call tal función volverá cuando la función alcanza el final del archivo o un explícita o exit /bgoto :eof (como su goto :end).

Por lo tanto, no puede cancelar su lote si usa una etiqueta como función.

Sin embargo, goto a una etiqueta, no devolver a la persona que llama.

Pero también hay una forma de salir del lote desde la función .
Puede crear un error de sintaxis, esto fuerza al lote a detenerse.

@echo off 
call :label hello 
call :label stop 
echo Never returns 
exit /b 

:label 
echo %1 
if "%1"=="stop" goto :halt 
exit /b 

:halt 
call :haltHelper 2> nul 

:haltHelper 
() 
exit /b 
+3

Además de la imposibilidad de volver a un script de proceso por lotes, esta solución también evita el ENDLOCAL implícito que se supone que ocurre al terminar el lote, lo que provoca cambios persistentes no deseados en el entorno. – dbenham

+0

Consulte http://stackoverflow.com/a/25474648/1012053 para obtener una técnica limpia para salir del procesamiento por lotes desde una rutina CALLed que finaliza adecuadamente SETLOCAL. – dbenham

5

La solución de jeb funciona muy bien. Pero puede no ser apropiado en todas las circunstancias. Tiene 2 inconvenientes potenciales:

1) El error de sintaxis se detendrá todo el procesamiento de lote. Entonces, si un script por lotes llamó a su script, y su script se detuvo con el error de sintaxis, entonces el control no se devuelve al llamador. Eso podría ser malo.

2) Normalmente, hay un ENDLOCAL implícito para cada SETLOCAL cuando finaliza el procesamiento por lotes. Pero el error de sintaxis fatal termina el procesamiento por lotes sin el ENDLOCAL implícito! Esto puede tener consecuencias desagradables :-(ver mis DosTips publicar SETLOCAL continues after batch termination! para más información.

actualización 2015-03-20Ver https://stackoverflow.com/a/25474648/1012053 de una forma limpia de terminar inmediatamente todo el procesamiento por lotes.

La otra forma de detener un archivo por lotes dentro de una función es usar el comando EXIT, que saldrá por completo del shell de comandos. Pero un poco de uso creativo de CMD puede hacer que sea útil para resolver el problema.

@echo off 
if "%~1" equ "_GO_" goto :main 
cmd /c ^""%~f0" _GO_ %*^" 
exit /b 

:main 
call :label hello 
call :label stop 
echo Never returns 
exit /b 

:label 
echo %1 
if "%1"=="stop" exit 
exit /b 

Tengo tanto mi versión llamada "daveExit.bat" y la versión de Jeb llamado "jebExit.bat" en mi PC.

luego ponerlos a prueba el uso de este script por lotes

@echo off 
echo before calling %1 
call %1 
echo returned from %1 

Y aquí están los resultados

>test jebExit 
before calling jebExit 
hello 
stop 

>test daveExit 
before calling daveExit 
hello 
stop 
returned from daveExit 

> 

Una desventaja potencial de la solución de salida es que los cambios en el medio ambiente no se conservan. Que pueden ser resueltos en parte por escribir el environent en un archivo temporal antes de salir, y luego leerlo de nuevo.

@echo off 
if "%~1" equ "_GO_" goto :main 
cmd /c ^""%~f0" _GO_ %*^" 
for /f "eol== delims=" %%A in (env.tmp) do set %%A 
del env.tmp 
exit /b 

:main 
call :label hello 
set junk=saved 
call :label stop 
echo Never returns 
exit /b 

:label 
echo %1 
if "%1"=="stop" goto :saveEnvAndExit 
exit /b 

:saveEnvAndExit 
set >env.tmp 
exit 

Pero variables con carácter de nueva línea (0x0A) en el valor no se conservan adecuadamente.

+0

+1, también es bueno, y tiene la ventaja de que las variables temporales se eliminan – jeb

+0

@jeb - Estaba pensando que la pérdida de la configuración de la variable de entorno podría ser una desventaja. Pero veo tu punto. Puede haber cualquier cantidad de configuraciones de variables temp antes de la condición de salida que no deberían conservarse. Si hay variables que deben conservarse, pueden escribirse selectivamente en un archivo temporal y restaurarse cuando CMD regrese. – dbenham

1

aquí está mi solución que va a apoyar rutinas anidadas si todo se comprueba su nivel de error agrego la prueba para errolevel en todas mis llamadas (internas o externas)

@echo off 
call :error message&if errorlevel 1 exit /b %errorlevel%< 
@echo continuing 
exit /b 0 
:error 
@echo in %0 
@echo message: %1 
set yes= 
set /p yes=[no]^|yes to continue 
if /i "%yes%" == "yes" exit /b 0 
exit /b 1 
+0

Aprendí algo nuevo de tu publicación. El eco del% 0 es algo sobre lo que nunca estoy nuevo (para una función). ¡Gracias! – djangofan

1

Si utiliza exit /b X a salir de la función luego establecerá ERRORLEVEL en el valor de X. A continuación, puede usar ||conditional processing symbol para ejecutar un comando si ERRORLEVEL es distinto de cero.

@echo off 
setlocal 
call :myfunction PASS || goto :eof 
call :myfunction FAIL || goto :eof 
echo Execution never gets here 
goto :eof 

:myfunction 
    if "%1"=="FAIL" ( 
     echo myfunction: got a FAIL. Will exit. 
     exit /b 1 
    ) 
    echo myfunction: Everything is good. 
    exit /b 0 

La salida de este script es:

myfunction: Everything is good. 
myfunction: got a FAIL. Will exit. 
Cuestiones relacionadas