已达到最大 setlocal 递归级别 & endlocal。解决方法?

Maximum setlocal recursion level reached & endlocal. Workaround?

我有一段代码被执行了 0-100,000 次。有问题的块显示如下:

FOR /R %%f IN (*.*) DO (
  CLS
  ECHO Del 2.0
  ECHO Files Done^: !FILES_DONE! / !FILES_TOTAL!
  ECHO Missing^: !FILES_MISSING!
  SETLOCAL DisableDelayedExpansion
  SET "FILES_TEMP=%%f"
  SETLOCAL EnableDelayedExpansion
  IF EXIST "!FILES_TEMP!" (
    !DELITE! -p 13 -q "!FILES_TEMP!" >NUL
    SET /A FILES_DONE += 1
  ) ELSE (
    SET /A FILES_MISSING += 1
  )
)

在此块中:!FILES_DONE!!FILES_TOTAL!!FILES_MISSING! 都是整数变量。

!DELITE! 是对可执行文件的引用:“!CD!\_sdelete.exe”,其中“!CD!”是执行批处理的根文件夹。

注意:请注意,打开 DelayedExpansion on/off 是必要的,因为我需要捕获可能包含或不包含特殊字符的文件名,例如:“!”和“^”。

所以我的问题是:如何重新格式化此代码块以不抛出“已达到最大递归级别”错误? (我知道这个问题被问的频率有多高,这只是我问题的一半,所以请耐心等待)

其次,有人可以解释一下这段代码在本地环境中的作用吗?

SETLOCAL EnableDelayedExpansion
FOR /R %%f IN (*.*) DO (
  ECHO !FILES_DONE! / !FILES_TOTAL!
  ENDLOCAL & (
    SET "FILES_TEMP=%%f"
  )
  [etc...]
)

例如,一旦它循环了一次代码,'endlocal' 是否仍然有效,还是会恢复,因为它是一个新循环?此外,它是否有助于达到最大 Setlocal 级别?

###########################################################################################

Del 2.0 - 完整文件内容供任何想使用它的人使用
注意:如果有人想要 Del Batch 的更新副本,请给我发消息;目前为V3.0-R0,需要使用sdelete.exe command-line utility from Microsoft。我最终可能会将其托管在一个网站上,作为任何想要安全删除程序的人的免费扩展。

@ECHO OFF
SETLOCAL EnableDelayedExpansion
TITLE Del 2.0
GOTO PRECHECK

:PRECHECK
ECHO Del 2.0
ECHO Checking...
IF NOT EXIST "!CD!\To-Do" (
  ECHO To-Do Folder Not Found
  ECHO.
  ECHO Nothing To Delete
  PAUSE >NUL
  GOTO END
)
IF NOT EXIST "!CD!\_sdelete.exe" (
  ECHO SDelete Program Not Found
  ECHO.
  ECHO Core File "_sdelete.exe" Missing
  PAUSE >NUL
  GOTO END
) ELSE (
  ATTRIB +S +H "!CD!\_sdelete.exe" >NUL
)
TIMEOUT /T 1 /NOBREAK >NUL
GOTO SETVARS

:SETVARS
CLS
ECHO Del 2.0
ECHO Writing Variables...
SET TAB=    
SET FILES_TEMP=0
SET FILES_TOTAL=0
SET FILES_DONE=0
SET FILES_MISSING=0
SET ROOTCD=!CD!
SET HOMECD=!CD!\To-Do
SET DELITE="!CD!\_sdelete.exe"
TIMEOUT /T 1 /NOBREAK >NUL
GOTO START

:START
CLS
ECHO Del 2.0
ECHO Starting...
ATTRIB -S -H ** /S /D
CD To-Do
TIMEOUT /T 1 /NOBREAK >NUL
CLS
ECHO Del 2.0
ECHO Counting Files...
FOR /R %%f IN (**) DO (
  CLS
  SET /A FILES_TOTAL += 1
  ECHO Del 2.0
  ECHO Files Found^: !FILES_TOTAL!
)
TIMEOUT /T 1 /NOBREAK >NUL
GOTO ERASEFILES

:ERASEFILES
CLS
ECHO Del 2.0
ECHO Erasing Files...
SETLOCAL DisableDelayedExpansion
FOR /R %%f IN (*.*) DO (
  SET "FILES_TEMP=%%f"
  CALL :SUBERASE
)
GOTO FINISHERASE

:SUBERASE
CLS
ECHO Del 2.0
ECHO Files Done^: %FILES_DONE% / %FILES_TOTAL%
ECHO Missing^: %FILES_MISSING%
IF EXIST "%FILES_TEMP%" (
  %DELITE% -p 13 -q "%FILES_TEMP%" >NUL
  SET /A FILES_DONE += 1
) ELSE (
  SET /A FILES_MISSING += 1
)
EXIT /B

:FINISHERASE
SETLOCAL EnableDelayedExpansion
CLS
ECHO Del 2.0
ECHO Files Done^: !FILES_DONE! / !FILES_TOTAL!
ECHO Missing^: !FILES_MISSING!
TIMEOUT /T 3 /NOBREAK >NUL
GOTO CLEANUP

:CLEANUP
CLS
ECHO Del 2.0
ECHO Cleaning Up...
IF !FILES_MISSING! EQU 0 (
  FOR /D %%f in (*.*) DO (
    SETLOCAL DisableDelayedExpansion
    SET "FILES_TEMP=%%f"
    SETLOCAL EnableDelayedExpansion
    RD "!FILES_TEMP!" /S /Q >NUL
  )
)
TIMEOUT /T 1 /NOBREAK >NUL
GOTO END

:END
CLS
ECHO Del 2.0
ECHO Complete^^!
TIMEOUT /T 3 /NOBREAK >NUL
EXIT

保持Delayed Expansion disabled using call command如下:

@ECHO OFF
SETLOCAL EnableExtensions DisableDelayedExpansion
FOR /R %%f IN (*.*) DO (
  SET "FILES_TEMP=%%f"
  CALL :doAll
)
goto :skipSubroutine

:doAll
  CLS
  ECHO Del 2.0
  ECHO Files Done^: %FILES_DONE% / %FILES_TOTAL%
  ECHO Missing^: %FILES_MISSING%
  IF EXIST "%FILES_TEMP%" (
    %DELITE% -p 13 -q "%FILES_TEMP%" >NUL
    SET /A FILES_DONE += 1
  ) ELSE (
    SET /A FILES_MISSING += 1
  )
goto :eof

:skipSubroutine

如果 FILES_TEMP 变量 需要 Delayed Expansion enabled 那么 :doAll 子例程可能如下所示(注意 ENDLOCAL 命令是使用两次以在脚本范围内正确更新变量 FILES_DONEFILES_MISSING):

:doAll
  CLS
  ECHO Del 2.0
  ECHO Files Done^: %FILES_DONE% / %FILES_TOTAL%
  ECHO Missing^: %FILES_MISSING%
  SETLOCAL EnableDelayedExpansion
  IF EXIST "!FILES_TEMP!" (
    %DELITE% -p 13 -q "!FILES_TEMP!" >NUL
    ENDLOCAL
    SET /A FILES_DONE += 1
  ) ELSE (
    ENDLOCAL
    SET /A FILES_MISSING += 1
  )
goto :eof