web-dev-qa-db-ja.com

バッチファイルのFORループを終了しますか?

このバッチファイルがループから抜け出さないのはなぜですか?

For /L %%f In (1,1,1000000) Do @If Not Exist %%f Goto :EOF

Goto :EOFループから抜け出しますか?

編集:

もっと明示的に尋ねるべきだったと思います... howループから抜け出すことができますか?

22
Mehrdad

Timの2番目の編集 および このページ に基づいて、これを行うことができます。

@echo off
if "%1"=="loop" (
  for /l %%f in (1,1,1000000) do (
    echo %%f
    if exist %%f exit
  )
  goto :eof
)
cmd /v:on /q /d /c "%0 loop"
echo done

このページ はループ内でgotoを使用する方法を提案します。動作するようですが、大きなループでは時間がかかります。したがって、gotoが実行される前に内部的にループを終了します。

7
wimh

単にecho onを使用すると、goto :eofまたはexit /bでさえ期待どおりに動作しないことがわかります。

ループ内のコードは実行されなくなりましたが、ループはすべての数値に対して最後まで展開されます。
だからこそとても遅いのです。

FOR/Lループを終了する唯一の方法は、Wimmelのexsampleのようなexitのバリアントのようですが、これはループの結果にアクセスするのに非常に高速でも便利でもありません。

これは10個の展開を示していますが、いずれも実行されません

echo on
for /l %%n in (1,1,10) do (
  goto :eof
  echo %%n
)
6
jeb

だからこれはちょっと古いことを理解していますが、多くのグーグルの後、私は満足している答えを見つけることができませんでしたので、反復をすぐに停止するFORループを壊すための独自のソリューションを考え出し、共有したいと思いましたそれ。

ループは別のファイルにある必要があり、CMDエラー処理のバグを悪用して、DIRのSTDOUTをSTDINにリダイレクトするときにループファイルのバッチ処理をすぐにクラッシュさせます。

MainFile.cmd

ECHO Simple test demonstrating loop breaking.
ECHO.
CMD /C %~dp0\LOOP.cmd
ECHO.
ECHO After LOOP
PAUSE

LOOP.cmd

FOR /L %%A IN (1,1,10) DO (
    ECHO %%A
    IF %%A EQU 3 DIR >&0 2>NUL  )
)

実行すると、次の出力が生成されます。 %A = 3の場合、ループの反復と実行の両方が停止することがわかります。

:>MainFile.cmd

:>ECHO Simple test demonstrating loop breaking.
Simple test demonstrating loop breaking.

:>ECHO.


:>CMD /C Z:\LOOP.cmd

:>FOR /L %A IN (1 1 10) DO (
ECHO %A
 IF %A EQU 3 DIR         1>&0 2>NUL
)

:>(
ECHO 1
 IF 1 EQU 3 DIR          1>&0 2>NUL
)
1

:>(
ECHO 2
 IF 2 EQU 3 DIR          1>&0 2>NUL
)
2

:>(
ECHO 3
 IF 3 EQU 3 DIR          1>&0 2>NUL
)
3

:>ECHO.


:>ECHO After LOOP
After LOOP

:>PAUSE
Press any key to continue . . .

ループから単一の変数を保持する必要がある場合は、ループにその変数の結果をECHOさせ、MainFile.cmdでFOR/Fループを使用してLOOP.cmdファイルの出力を解析します。

例(上記と同じLOOP.cmdファイルを使用):

MainFile.cmd

@ECHO OFF
ECHO.
ECHO Simple test demonstrating loop breaking.
ECHO.
FOR /F "delims=" %%L IN ('CMD /C %~dp0\LOOP.cmd') DO SET VARIABLE=%%L
ECHO After LOOP
ECHO.
ECHO %VARIABLE%
ECHO.
PAUSE

出力:

:>MainFile.cmd

Simple test demonstrating loop breaking.

After LOOP

3

Press any key to continue . . .

複数の変数を保持する必要がある場合は、以下に示すように一時ファイルにリダイレクトする必要があります。

MainFile.cmd

@ECHO OFF
ECHO.
ECHO Simple test demonstrating loop breaking.
ECHO.
CMD /C %~dp0\LOOP.cmd
ECHO After LOOP
ECHO.
SET /P VARIABLE1=<%TEMP%\1
SET /P VARIABLE2=<%TEMP%\2
ECHO %VARIABLE1%
ECHO %VARIABLE2%
ECHO.
PAUSE

LOOP.cmd

@ECHO OFF
FOR /L %%A IN (1,1,10) DO (
    IF %%A EQU 1 ECHO ONE >%TEMP%\1
    IF %%A EQU 2 ECHO TWO >%TEMP%\2
    IF %%A EQU 3 DIR >&0 2>NUL
)

出力:

:>MainFile.cmd

Simple test demonstrating loop breaking.

After LOOP

ONE
TWO

Press any key to continue . . .

他の人が、反復を継続するために終了するのに時間がかかりすぎるループを壊すのに役立つことを願っています。

2
John Hofmann

jebnoted のように、ループの残りの部分はスキップされますが、評価されます。これによりFORが作成されます。この目的にはソリューションが遅すぎます。別の方法:

set F=1
:nextpart
if not exist "%F%" goto :EOF
echo %F%
set /a F=%F%+1
goto nextpart

ループでこれを使用する場合は、 遅延展開 およびcallサブルーチンを使用する必要があります。

2

OPがcmd.exeでバッチファイルを呼び出し、forループから適切に抜け出すために、ラベルに移動すると仮定します。

これを変える:

For /L %%f In (1,1,1000000) Do If Not Exist %%f Goto :EOF

これに:

For /L %%f In (1,1,1000000) Do If Not Exist %%f Goto:fileError
.. do something
.. then exit or do somethign else

:fileError
GOTO:EOF

さらに良いことに、エラー報告をいくつか追加します。

set filename=
For /L %%f In (1,1,1000000) Do(
    set filename=%%f
    If Not Exist %%f set tempGoto:fileError
)
.. do something
.. then exit or do somethign else

:fileError
echo file does not exist '%filename%'
GOTO:EOF

これはあまり知られていないcmd.exe/DOSバッチファイルの機能とトリックに関する役立つサイトであることがわかりました。 https://www.dostips.com/

0
The Coordinator

これについて少し調べたところ、1から2147483647まで1ずつループしているようです。

(1、1、2147483647):最初の番号は開始番号、次の番号はステップ、最後の番号は終了番号です。

追加して編集

テスト条件に関係なく、ループは最後まで実行されるようです。テストした

FOR /L %%F IN (1, 1, 5) DO SET %%F=6

そして、それは非常に迅速に実行されました。

2番目の編集

これはバッチファイルの唯一の行であるため、EXITコマンドを試すことができます。

FOR /L %%F IN (1, 1, 2147483647) DO @IF NOT EXIST %%F EXIT

ただし、これにより、DOSプロンプトウィンドウも閉じられます。

0
Tim