FOR ループ内のサイクルをスキップするにはどうすればよいですか?

FOR ループ内のサイクルをスキップするにはどうすればよいですか?

いくつかのファイルを処理するためのバッチ スクリプトを実行しています。現在のファイルに処理が必要ないと判断した場合、そのファイルの残りのコマンドをスキップして、次のファイルに直接移動したいと思います。どうすればよいでしょうか。両方Goto :EOFともexit /bスクリプト全体を終了します。

これがスクリプトです。ディレクトリを取得し、ファイル名にすでに含まれている単語を除く、親ディレクトリ名のすべての単語を含むようにすべてのファイルの名前を変更します。

@echo off
setlocal enabledelayedexpansion

rem set input directory (add check for validity)
set "inputDir=%~1"
set "confirmation=false"

:proceed
for /r "%inputDir%" %%F in (*.*) do (
    rem use path to file as keywords
    set "words=%%~pF"
    rem replace known useless marks with spaces
    set "words=!words:\= !"
    set "words=!words:_= !"
    set "words=!words:,= !"
    set "words=!words:  = !"
    rem remove known useless words
    set "words=!words: The = !"
    set "words=!words: A = !"
    set "words=!words: An = !"
    set "words=!words: Video = !"
    set "words=!words: New Folder = !"
    rem remove word that already exists in the filename
    for %%W in (!words!) do echo %%~nF | find /i "%%W" >nul && set "words=!words: %%W = !"
    rem replace leading and trailing spaces with brackets
    set "words=[!words:~1,-1!]"
    rem if all words already included end task for current file
    if "!words!"=="[]" exit /b
    rem build the new filename
    set "newName=%%~nF !words!%%~xF"
    rem fix "] [" caused by repeated renaming, causes fusion with non-related bracketed sets, which is fine
    set "newName=!newName:] [= !"
    rem task for displaying the name change for confirmation
    if /i not "%confirmation%"=="yes" echo old "%%F" && echo new "!newName!"
    rem task for doing the actual rename if confirmed
     if /i "%confirmation%"=="yes" echo ren "%%~nxF" "!newName!" & echo ren "%%F" "!newName!"
)

rem fails to rename files with ! mark in the filename. no other trouble, just won't rename those. error: the syntax of the command is incorrect

rem if coming from second (completed) run then exit
if /i "%confirmation%"=="yes" exit /b
rem ask for confirmation to run again for real
set /p confirmation="confirm you want to perform all these rename tasks (type yes or no)?: "
if /i not "%confirmation%"=="yes" echo confirmation denied
if /i "%confirmation%"=="yes" goto proceed

endlocal

私はまた、最後のコマンドを条件付きで実行する別の方法を試しています。

@echo off
setlocal enabledelayedexpansion

rem set input directory (add check for validity)
set "inputDir=%~1"
set "confirmation=false"

:proceed
for /r "%inputDir%" %%F in (*.*) do (
    rem use path to file as keywords
    set "words=%%~pF"
    rem replace known useless marks with spaces
    set "words=!words:\= !"
    set "words=!words:_= !"
    set "words=!words:,= !"
    set "words=!words:  = !"
    rem remove known useless words
    set "words=!words: The = !"
    set "words=!words: A = !"
    set "words=!words: An = !"
    set "words=!words: Video = !"
    set "words=!words: New Folder = !"
    rem remove word that already exists in the filename
    for %%W in (!words!) do echo %%~nF | find /i "%%W" >nul && set "words=!words: %%W = !"
    rem replace leading and trailing spaces with brackets
    set "words=[!words:~1,-1!]"
    rem if all words not already included in the filename do
    if not "!words!"=="[]" (
        rem build the new filename
        set "newName=%%~nF !words!%%~xF"
        rem fix "] [" caused by repeated renaming, causes fusion with non-related bracketed sets, which is fine
        set "newName=!newName:] [= !"
        rem task for displaying the name change for confirmation
        if /i not "%confirmation%"=="yes" echo old "%%F" && echo new "!newName!"
        rem task for doing the actual rename if confirmed
        if /i "%confirmation%"=="yes" echo ren "%%~nxF" "!newName!" & echo ren "%%F" "!newName!"
    )
)

rem fails to rename files with ! mark in the filename. no other trouble, just won't rename those. error: the syntax of the command is incorrect

rem if coming from second (completed) run then exit
if /i "%confirmation%"=="yes" exit /b
rem ask for confirmation to run again for real
set /p confirmation="confirm you want to perform all these rename tasks (type yes or no)?: "
if /i not "%confirmation%"=="yes" echo confirmation denied
if /i "%confirmation%"=="yes" goto proceed

endlocal

しかし、これは大惨事であり、ファイル名のランダムな部分が切り取られ、words追加されたように見えるファイル名が生成されます。

答え1

for ループ本体内の最後のステートメントとしてラベル:nextiteration(または任意の名前) を配置し、gotofor 本体の残りの部分をスキップできると判断したときにそのラベルに配置します。

FOR 本体の閉じ括弧の前に通常のステートメントを置く必要があるため (ラベルは使用できません)、ラベルと閉じ括弧の間にダミー ステートメント (REM など) を配置する必要があります。

FOR xxxxxxxxx DO (
  some statements (executed on each iteration)
  IF {some condition is met} GOTO nextiteration
  statements that will be skipped if conditon is met
:nextiteration
  REM to prevent syntax error
)

答え2

Windows バッチには、ループの反復をスキップするためのオプションはあまり多くありません。使用できる方法は次のとおりです。

  • スキップしたいループの部分に IF ブロックを配置します。

    @Echo Off
    if A equ A (
      IF B==C (
        Echo shouldn't go here
      )
    )
    
  • call内部ループ全体を含むルーチンを呼び出すために使用しますexit/B。ここでは次のように機能します。

     @Echo Off
     Setlocal 
     For %%A in (alpha beta gamma) DO (
       Echo Outer loop %%A
       Call :inner 
     )
     Goto :eof
    
     :inner
     For %%B in (U V W X Y Z) DO (
       if %%B==X ( exit /b 2 )
       Echo    Inner loop    Outer=%%A Inner=%%B
     )
    
  • コマンドを使用してgoto :LabelLabel: ループの最後に配置します。既知のバグのため、これはおそらく機能しません。FOR コマンドや IF コマンドを含む括弧内で GOTO を使用すると、機能しなくなります。
    バグを示す例:

    @Echo Off
    if A equ A (
      IF B==C GOTO specialcase 
        Echo shouldn't go here
        goto:eof 
    :specialcase
    )
    

参照 :

答え3

使ってみてFor /F...ください... | findstr /c:"string1" /c:"string2"...

文字列をフィルタリングし、結果として得られる相互ファイル名を使用してアクションをより細かく制御できるループを使用します。これにより、ループをより正確にスキップせずに、名前を変更する操作を簡単に実行できるようになります。

@echo off & setlocal

2>nul cd /d "%~1" || exit 

setlocal enabledelayedexpansion

for %%G in =;( 
     "_",",","  "," The "," A "," An "," Video "," New Folder " 
    );= do if not defined _str2find =;( set "_str2find=/c:"%%~G""
        );= else call set "_str2find=!_str2find! /c:"%%~G""

setlocal disabledelayedexpansion

for /f usebackq^delims^= %%G in (`
    2^>nul where /r . *.* ^| findstr %_str2find% `);= do =;( 
      echo/%%~G 
      :: So you don't need to use skip, the rest of your 
      :: interactions continue here and within your loop 
     );=

endlocal 

関連情報