サブルーチンからバッチファイルを終了する


20

サブルーチン内からバッチファイルを終了するにはどうすればよいですか?

EXITコマンドを使用すると、サブルーチンを呼び出した行に戻るだけで、実行が継続されます。

以下に例を示します。

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

:QUIT
EXIT /B 1

:END
EXIT /B 0

出力:

Quitting...
Still here!

更新:

これは適切な答えではありませんが、最終的に次のようなことに沿って何かをすることになりました。

@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

以下の二重パイプステートメント:

CALL :SUBROUTINE_WITH_ERROR || GOTO HANDLE_FAIL

以下の略記です:

CALL :SUBROUTINE_WITH_ERROR 
IF ERRORLEVEL 1 GOTO HANDLE_FAIL    

CALLERに状況を処理させるのではなく、サブルーチンから直接終了する方法があるかどうかを知りたいのですが、これで少なくとも作業は完了します。


更新#2:上記の方法で呼び出された別のサブルーチン内からサブルーチンを呼び出すとき、このようにサブルーチン内から呼び出します:

CALL :SUBROUTINE_WITH_ERROR || EXIT /B 1

このようにして、エラーはいわば「メイン」に伝播します。バッチの主要部分は、エラーハンドラーGOTO:FAILUREでエラーを処理できます

回答:


21

これをバッチファイルの先頭に追加します。

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

次に、単に呼び出すことができます:

  • EXIT [errorLevel] ファイル全体を終了する場合
  • EXIT /B [errorLevel] 現在のサブルーチンを終了する
  • GOTO :EOF 現在のサブルーチンを終了する

実際に言及するための+1GOTO :EOF
afrazier

1
非常に素晴らしい。私は小さな変更を加えました:%~0ではなく変数に割り当てます。そうすれば、お互いを呼び出す複数のバッチスクリプトで同じトリックを使用できます。trueif not "%selfwrapped%"=="%~0" ( set selfwrapped=%~0 .... )
GolezTrol

これは素晴らしい解決策です。どのように機能するかを説明するのは編集する価値があると思いますか?すべてを解凍して、ネストされたcmd.exeから%~0すべての引数(%*)でバッチファイル()を呼び出しているだけで/s%ComSpec%引数が二重引用符を処理する方法を制御するために使用されていることに気付きコール。
ショーン

@Sean簡潔さはほとんどの人にとってより便利だと思います。私が書いてから7年間、より多くのドキュメントが要求されなかったので、高い需要がないようです。また、ドキュメントを複製したり断片化したりせずに、自分で物事を調べている人にとっても価値があると思います。しかし、もしもっと多くの人が尋ねたら、何か追加できるかもしれません。あなたも編集を提案することができるようにそれはまた、CWだ
メルリンモルガン・グラハム

3

このちょっとした調整はいかがですか?

@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

出力:

Quitting...

技術的には、これはサブルーチン内から終了しません。むしろ、単にサブルーチンの結果を確認し、そこからアクションを実行します。


2
おかげで、それは確かに仕事を成し遂げるでしょう。もし私がより良い答えを見つけられなければ、それは私がしなければならないことです。ただし、長くて複雑なバッチファイルの各CALLの後にその行を貼り付ける必要はありません。
ブラウン

1

手順から戻らない場合は、call代わりにを使用してくださいgoto

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

:QUIT
EXIT /B 1

:END
EXIT /B 0

質問のポイントは、サブルーチンからどのように実行するか(つまり呼び出しを使用する)であるため、これは応答しません。
スティーブクレーン

1

バッチファイルにエラー処理を入れました。次のようなエラーハンドラを呼び出すことができます。

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

そして、これがバッチファイルの終わりです。

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

これにより、現在のコンテキストと親コンテキストが終了します(つまり、1つのcall深いサブルーチンスクリプト内で実行されると終了します)。

(goto) 2>nul || exit /b

または、エラーレベル0が必要な場合:

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

基本的に、(goto) 2>nulerrorlevelを1 に設定し(エラーを出力せずに)、親コンテキストで実行を返し、親コンテキストでダブルパイプが実行された後にコードを返します。type nul>nulerrorlevelを0に設定します。

UPD:

実行を2回以上連続して返すには、次の(goto) 2>nul ||ようにいくつかをチェーンします。

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

コンテキストを可変回数返す再帰サブルーチンは次のとおりです。

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

再帰関数から呼び出された場合:

@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

出力は次のようになります。

1
2
3
4
5
This will be printed only once
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.