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

时间:2016-06-11 16:13:48

标签: batch-file recursion cmd batch-processing command-prompt

我有一段代码正在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是必要的,因为我需要捕获可能有或没有特殊字符的文件名,例如:“!”和“^”。

所以我的问题是:如何重新格式化此代码块以避免抛出Maximum Recursion Level Reached错误? (我知道这问题的频率是多少,这只是我问题的一半,所以请耐心等待)

其次,有人可以解释这段代码如何在本地环境中发挥作用吗?

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

例如,一旦它遍历代码一次,'endlocal'是否仍然有效,或者它将被恢复,因为它是一个新的循环?此外,它是否有助于达到最大Setlocal Level?

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

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

1 个答案:

答案 0 :(得分:3)

使用Delayed Expansion禁用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