15

ディレクトリをチェックするために書かれた簡単な関数があります:

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

:end は次のように記述されます

:end
endlocal

goto:end が呼び出された後にプログラムが停止しない理由がわかりません。同じメソッドを使用してプログラムを停止する別の関数があり、正常に動作します。

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

この場合、プログラムは :end; を呼び出した後に停止します。これが :direxist で機能しないのはなぜですか? ご協力ありがとうございました!

4

4 に答える 4

18

私はあなたがここで混合callgotoステートメントをしていると思います。

callバッチ ファイル内のラベルはまたはと一緒に使用できますgotoが、動作は異なります。
そのcallような関数exit /bの場合、関数がファイルの終わりまたは明示的なor goto :eof(あなたの のように)に達したときに戻りますgoto :end

したがって、ラベルを関数として使用する場合、バッチをキャンセルすることはできません。

ただし、gotoラベルには、呼び出し元には戻りません。

synatx エラーの使用:

しかし、関数からバッチを終了する方法もあります。
構文エラーを作成できます。これにより、バッチが強制的に停止されます。
ただし、ローカル (setlocal) 変数が削除されないという副作用があります。

@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

CTRL-C を使用:

CTRL-C エラーコードに似たエラーコードを作成すると、バッチ処理も停止します。
終了後、setlocal の状態はcleanです!
@dbenham の回答を参照関数内からバッチ スクリプトを終了する

高度な例外処理の使用:

これは、任意の量のスタック レベルを削除できるため、最も強力なソリューションです。現在のバッチ ファイルのみを終了し、スタック トレースを表示するためにも使用できます。
これは、(goto)が引数なしでスタックから 1 つの要素を削除するという事実を利用しています。Windows バッチは例外処理をサポートしていますか?
を参照してください。

于 2012-05-10T13:44:45.903 に答える
5

jebのソリューションはうまく機能します。しかし、すべての状況で適切であるとは限りません。潜在的な欠点が 2 つあります。

1) 構文エラーにより、すべてのバッチ処理が停止します。したがって、バッチ スクリプトがスクリプトを呼び出し、スクリプトが構文エラーで停止した場合、制御は呼び出し元に返されません。それは悪いかもしれません。

2) 通常、バッチ処理が終了すると、すべての SETLOCAL に対して暗黙の ENDLOCAL が存在します。しかし、致命的な構文エラーにより、暗黙の ENDLOCAL !なしでバッチ処理が終了します。これは厄介な結果をもたらす可能性があります :-( 詳細については、DosTips のポスト「バッチ終了後に SETLOCAL が続行されます! 」を参照してください。

更新 2015-03-20 すべてのバッチ処理をすぐに終了するクリーンな方法については、https: //stackoverflow.com/a/25474648/1012053を参照してください。

関数内でバッチ ファイルを停止するもう 1 つの方法は、コマンド シェルを完全に終了する EXIT コマンドを使用することです。しかし、CMD を少し創造的に使用すると、問題の解決に役立ちます。

@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

私の PC には、「daveExit.bat」という名前の私のバージョンと「jebExit.bat」という名前の jeb のバージョンの両方があります。

次に、このバッチ スクリプトを使用してそれらをテストします

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

そして、これが結果です

>test jebExit
before calling jebExit
hello
stop

>test daveExit
before calling daveExit
hello
stop
returned from daveExit

>

EXIT ソリューションの潜在的な欠点の 1 つは、環境への変更が保持されないことです。これは、終了する前に環境を一時ファイルに書き込んでから読み戻すことで部分的に解決できます。

@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

ただし、値に改行文字 (0x0A) を含む変数は適切に保持されません。

于 2012-05-10T15:33:17.067 に答える
1

すべてのエラーレベルがチェックされている場合、ネストされたルーチンをサポートするソリューションを次に示します。すべての呼び出し (内部または外部) でエラーレベルのテストを追加します。

@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
于 2013-01-08T19:29:50.093 に答える