【发布时间】:2019-01-31 08:41:18
【问题描述】:
如何遍历目录树并删除所有目录,除非它们包含具有特定文件扩展名的文件?
我尝试 Robocopy 认为文件夹是空的。但是所有文件夹都有隐藏文件。因此,我需要一些东西,例如将目录中没有 .pdf 的目录中的每个文件夹删除并删除。
【问题讨论】:
标签: windows batch-file recursion cmd directory
如何遍历目录树并删除所有目录,除非它们包含具有特定文件扩展名的文件?
我尝试 Robocopy 认为文件夹是空的。但是所有文件夹都有隐藏文件。因此,我需要一些东西,例如将目录中没有 .pdf 的目录中的每个文件夹删除并删除。
【问题讨论】:
标签: windows batch-file recursion cmd directory
任务是删除所有不包含 PDF 文件且不包含包含 PDF 文件的子目录/子文件夹的目录/文件夹。让我们看一个例子来更好地理解目录/文件夹删除任务。
目录C:\Temp包含以下子文件夹和文件:
文件夹的格式为粗体。 隐藏文件夹的格式为粗体和斜体。隐藏的文件是斜体格式。
运行批处理文件后想要的文件夹和文件应该是:
这个结果可以通过执行以下批处理文件来实现:
@echo off
goto MainCode
:ProcessFolder
for /F "delims=" %%I in ('dir "%~1" /AD /B 2^>nul') do call :ProcessFolder "%~1\%%I"
if exist "%~1\*.pdf" goto :EOF
for /F "delims=" %%I in ('dir "%~1" /AD /B 2^>nul') do goto :EOF
if /I "%~1\" == "%BatchFilePath%" goto :EOF
rd /Q /S "%~1"
goto :EOF
:MainCode
setlocal EnableExtensions DisableDelayedExpansion
set "BatchFilePath=%~dp0"
if exist "C:\Temp\" cd /D "C:\Temp" & call :ProcessFolder "C:\Temp"
endlocal
在目录树上递归地做某事需要有一个递归调用自身的子例程/函数/过程。在上面的批处理文件中,这是ProcessFolder。
请阅读Where does GOTO :EOF return to? 上的答案。命令goto :EOF 在此处用于退出子程序ProcessFolder,并且仅在启用命令扩展的情况下按需要工作。此处使用的 FOR 和 CALL 也需要启用命令扩展。
批处理文件的主要代码首先明确启用此批处理文件所需的命令扩展,并禁用延迟的环境变量扩展以处理名称中带有感叹号的正确文件夹。这是 Windows 上的默认环境,但最好在此处显式设置此环境,因为批处理文件包含命令 RD 和选项 /Q /S,这对错误执行可能非常有害环境或目录。
子例程ProcessFolder 不像往常一样位于批处理文件的末尾,上面有goto :EOF,以避免在完成整个任务后意外掉入子例程的命令行。出于安全原因,子程序位于批处理文件的中间。因此,如果用户尝试在不支持命令扩展的情况下在 Windows 95/98 上执行批处理文件,则不会发生任何坏事,因为第一个 goto MainCode 按预期成功执行,但是 SETLOCAL 命令行调用子例程最后也是 ENDLOCAL 失败,所以这个为 Windows 设计的批处理文件没有删除任何目录,cmd.exe 作为 Windows 命令处理器而不是command.com。
主代码还将当前目录设置为要处理的目录。所以C:\Temp 本身永远不会被这段代码删除,因为 Windows 会阻止删除一个目录,该目录是任何正在运行的进程的当前目录,或者包含由正在运行的进程打开的文件,并设置了文件访问权限以防止其他进程删除被进程打开的文件。
接下来调用带有参数C:\Temp 的子程序ProcessFolder 以递归方式处理此文件夹。
最后恢复初始环境,如果该目录仍然存在,则还包括启动批处理文件时的初始当前目录。
for /D 命令通常用于对目录的所有子目录执行某些操作。但这在这里是不可能的,因为 FOR 总是忽略具有隐藏属性集的目录和文件。出于这个原因,有必要使用命令 DIR 来获取当前目录中所有子目录的列表,包括具有隐藏属性集的目录。
命令行dir "%~1" /AD /B 2>nul 由FOR 在后台以cmd.exe /C 启动的单独命令进程中执行。这就是为什么这个批处理文件很慢的原因之一。另一个原因是一次又一次地调用子程序,导致cmd.exe内部一次又一次地保存和恢复环境。
请阅读有关Using Command Redirection Operators 的Microsoft 文章以了解2>nul 的解释。重定向运算符 > 必须在 FOR 命令行上使用插入字符 ^ 转义,以便在 Windows 命令解释器在执行命令 FOR 之前处理此命令行时被解释为文字字符> 在后台启动的单独命令进程中执行嵌入的dir 命令行。
对于目录中的每个子目录,子例程ProcessFolder 调用自身。如果目录不再包含一个子目录,则子例程中的第一个 FOR 循环将被保留。
然后子程序检查当前目录是否至少有一个*.pdf 文件。即使目录仅包含隐藏的 PDF 文件,此处使用的 IF 条件也为真。在这种情况下,子程序不做任何事情就退出了,因为该目录肯定包含一个PDF文件,因此必须根据文件夹删除任务的要求进行保存。
下一步检查当前目录是否仍然包含至少一个子目录,因为在这种情况下,当前目录也必须保留,因为它的子目录之一至少包含一个 PDF 文件。
最后子程序检查当前目录是否偶然包含批处理文件,因为该目录也必须保留以完成批处理文件的处理。
否则当前目录将被删除,所有文件不包含 PDF 文件和子目录,也不是当前正在运行的批处理文件,只要 Windows 不会因为缺少权限或共享访问冲突而阻止删除该目录.
请注意,批处理文件不会删除目录中未删除的其他文件,这也可以在示例中看到。
要了解所使用的命令及其工作原理,请打开命令提示符窗口,在其中执行以下命令,并仔细阅读每个命令显示的所有帮助页面。
call /?cd /?dir /?echo /?endlocal /?for /?goto /?if /?rd /?setlocal /?【讨论】: