首页 > 解决方案 > 如何删除目录中的所有文件和文件夹,分别删除整个目录树,列表文件中指定的文件除外?

问题描述

我想知道如何使用批处理文件解决以下问题。

删除里面的所有文件和文件夹,G:\AD\mods除了我要保留的所有文件和文件夹的列表。

有人对批处理文件解决方案有什么建议吗?

我在批处理文件中尝试了以下 Windows 命令行:

for %%i in (*.*) do if not "%%i"=="doc1.txt" if not "%%i"=="doc2.txt" del /q "%%i"

这可行,但我只能从放置批处理文件的同一文件夹中删除文件。

然后我读了这篇文章:使用批处理删除文件夹中的所有文件,但列表中的文件除外

它建议类似:

except 3.txt del temp /Q

这也适用于同一个文件夹,但不适用于目录树不同级别的文件和文件夹。

编辑:

我有一个包含大约 1000 个子文件夹的主文件夹。这些文件夹中也有子文件夹。相同的文件名可能存在于多个文件夹中。因此,我需要为要保留的每个文件指定确切的文件路径。

要保留的文件列表文件中的名称示例:

AD\mods\folder1\doc1.txt
AD\mods\folder1\subfolder1\doc1.txt
AD\mods\folder2\doc1.txt

批处理文件应删除所有其他文件。

PowerShell 解决方案也可以。

标签: batch-filecmd

解决方案


让我们假设列表文件G:\AD\mods\Exclusion List.txt仅包含没有路径的文件/文件夹名称,例如:

Cleanup.cmd
Exclusion List.txt
Folder to keep
File not to delete.txt

批处理文件G:\AD\mods\Cleanup.cmd可以与以下命令行一起使用,以删除批处理文件目录中的所有文件和文件夹,但排除列表文件中的文件和文件夹除外:

@echo off
setlocal EnableExtensions DisableDelayedExpansion
set "FolderPath=%~dp0"
for /F "eol=| delims=" %%I in ('dir "%FolderPath%" /AD /B 2^>nul ^| %SystemRoot%\System32\findstr.exe /I /L /V /X /G:"%FolderPath%Exclusion List.txt"') do rd /Q /S "%FolderPath%%%I"
for /F "eol=| delims=" %%I in ('dir "%FolderPath%" /A-D /B 2^>nul ^| %SystemRoot%\System32\findstr.exe /I /L /V /X /G:"%FolderPath%Exclusion List.txt"') do del /A /F "%FolderPath%%%I"
endlocal

第一个FOR命令行在后台启动的单独命令进程中运行,命令DIR输出批处理文件目录中的所有文件夹名称,使用FINDSTR过滤以从文件夹名称列表中排除排除列表文件中列出的所有文件夹名称。结果列表由运行命令RD以删除这些文件夹的FOR处理。

第二个FOR命令行在后台启动的单独命令进程中运行,命令DIR输出批处理文件目录中的所有文件名,使用FINDSTR过滤以从文件名列表中排除排除列表文件中列出的所有文件名。结果列表由FOR处理,它运行命令DEL以删除这些文件。

FOR选项用于避免忽略以分号开头的eol=|文件/文件夹名称,因为没有文件/文件夹名称可以包含竖线。FOR选项定义了一个空的delims=字符串分隔符列表,导致关闭默认行为,for /F即使用普通空格和水平制表符作为字符串分隔符将捕获的行拆分为子字符串(标记),并仅将第一个空格/制表符分隔的字符串分配给指定的循环变量I。该选项对于更正带有一个或多个空格的文件/文件夹名称也是必要的。


任务要求更改为删除整个目录树中的所有文件,除了在带有路径的排除列表文件中列出的文件(没有驱动器号和冒号)。

因此,让我们假设该文件G:\AD\mods\Exclusion List.txt包含以下几行。

G:\AD\mods\Cleanup.cmd
G:\AD\mods\Exclusion List.txt
AD\mods\folder1\doc1.txt
AD\mods\folder1\subfolder1\doc1.txt
AD\mods\folder2\doc1.txt

批处理文件G:\AD\mods\Cleanup.cmd可以与以下命令行一起使用,首先删除包含批处理文件和排除列表文件的目录的整个目录树中的所有文件,排除列表文件中的文件除外,然后递归删除所有目录不再包含至少一个文件。

@echo off
setlocal EnableExtensions DisableDelayedExpansion
set "FolderPath=%~dp0"
if "%FolderPath:~-1%" == "\" set "FolderPath=%FolderPath:~0,-1%"
for /F "delims=" %%I in ('dir "%FolderPath%" /A-D /B /S 2^>nul ^| %SystemRoot%\System32\findstr.exe /E /I /L /V /G:"%FolderPath%\Exclusion List.txt"') do del /A /F "%%I"
call :DeleteEmptyFolders "%FolderPath%"
goto EndBatch

:DeleteEmptyFolders
for /F "eol=| delims=" %%I in ('dir %1 /AD /B 2^>nul') do call :DeleteEmptyFolders "%~1\%%I"
for /F "eol=| delims=" %%I in ('dir %1 /A /B 2^>nul') do goto :EOF
rd /Q /S %1
goto :EOF

:EndBatch
endlocal

请注意,第一个FOR命令行中的FINDSTR选项/X被替换为过滤掉所有文件名的选项,这些文件名的完全限定名仅以排除列表文件中的一个字符串结尾,而不是匹配整个文件名,因为列表file 包含不带驱动器号和冒号的文件名。这可能会导致过滤错误,具体取决于文件完整路径的哪一部分在列表文件中。/E

那么这个批处理文件在驱动器上的以下目录树上会发生什么G:

  • 广告
    • 备份
      • 文件夹1
        • 子文件夹1
          • ;要保存的文件.txt
          • doc1.txt
        • doc1.txt
    • 模组
      • 文件夹1
        • 子文件夹1
          • ;要删除的文件.txt
          • doc1.txt
        • doc1.txt
        • 又一个文件!.txt
      • 文件夹2
        • 空子文件夹 1
        • 子文件夹 2
          • 另一个空文件夹
          • doc1.txt
        • doc1.txt
        • folder2().log 中的日志文件
      • 文件夹3
        • doc1.txt
      • 清理.cmd
      • 排除列表.txt
      • 自述文件.txt

的执行结果G:\AD\mods\Cleanup.cmd是:

  • 广告
    • 备份
      • 文件夹1
        • 子文件夹1
          • ;要保存的文件.txt
          • doc1.txt
        • doc1.txt
    • 模组
      • 文件夹1
        • 子文件夹1
          • doc1.txt
        • doc1.txt
      • 文件夹2
        • doc1.txt
      • 清理.cmd
      • 排除列表.txt

因此,保留其中的所有内容,G:\AD\backups并且G:\AD\mods仅保留名称在排除列表文件中列出的文件的文件夹,并且批处理脚本将删除所有其他文件和文件夹。

可以使用以下批处理代码创建目录和文件,但Cleanup.cmdExclusion List.txtin除外G:\AD\mods

@echo off
setlocal EnableExtensions DisableDelayedExpansion
set "BasePath=G:"
md "%BasePath%\AD\backups\folder1\subfolder1" 2>nul
md "%BasePath%\AD\mods\folder1\subfolder1" 2>nul
md "%BasePath%\AD\mods\folder2\Empty subfolder 1" 2>nul
md "%BasePath%\AD\mods\folder2\Subfolder 2\Another Empty Folder" 2>nul
md "%BasePath%\AD\mods\folder3" 2>nul
setlocal EnableDelayedExpansion
echo !BasePath!\AD\backups\folder1\subfolder1\;File to keep.txt>"!BasePath!\AD\backups\folder1\subfolder1\;File to keep.txt"
echo !BasePath!\AD\backups\folder1\subfolder1\doc1.txt>"!BasePath!\AD\backups\folder1\subfolder1\doc1.txt"
echo !BasePath!\AD\backups\folder1\doc1.txt>"!BasePath!\AD\backups\folder1\doc1.txt"
(echo !BasePath!\AD\mods\folder1\subfolder1\;File to delete.txt>"!BasePath!\AD\mods\folder1\subfolder1\;File to delete.txt") 2>nul
echo !BasePath!\AD\mods\folder1\subfolder1\doc1.txt>"!BasePath!\AD\mods\folder1\subfolder1\doc1.txt"
echo !BasePath!\AD\mods\folder1\doc1.txt>"!BasePath!\AD\mods\folder1\doc1.txt"
echo !BasePath!\AD\mods\folder1\One More File^^!.txt>"!BasePath!\AD\mods\folder1\One More File^!.txt"
(echo !BasePath!\AD\mods\folder2\Subfolder 2\doc1.txt>"!BasePath!\AD\mods\folder2\Subfolder 2\doc1.txt") 2>nul
echo !BasePath!\AD\mods\folder2\doc1.txt>"!BasePath!\AD\mods\folder2\doc1.txt"
echo !BasePath!\AD\mods\folder2\Log file in folder2().log>"!BasePath!\AD\mods\folder2\Log file in folder2().log"
echo !BasePath!\AD\mods\folder3\doc1.txt>"!BasePath!\AD\mods\folder3\doc1.txt"
echo !BasePath!\AD\mods\Readme.txt>"!BasePath!\AD\mods\Readme.txt"
endlocal
%SystemRoot%\System32\attrib.exe +r "%BasePath%\AD\mods\folder1\subfolder1\;File to delete.txt"
%SystemRoot%\System32\attrib.exe +h "%BasePath%\AD\mods\folder2\Subfolder 2\doc1.txt"
%SystemRoot%\System32\attrib.exe +h "%BasePath%\AD\mods\folder2\Empty subfolder 1"
%SystemRoot%\System32\attrib.exe +r +s +h "%BasePath%\AD\mods\folder3"
endlocal

文件夹的删除G:\AD\mods\folder3很棘手,因为它具有只读属性集(以及系统和隐藏属性),这会导致在子例程中的第一个FOR循环之后Access is denied.使用命令时出现错误消息,否则只会删除空文件夹。因此,使用第二个FOR循环在后台的单独命令进程中再次运行DIR 。如果目录不是空的,因为仍然包含文件或文件夹,则退出子程序。否则,该文件夹为空,即使设置了只读属性,也用于删除空文件夹。rd %1 2>nulDeleteEmptyFoldersrd /Q /S %1


要了解使用的命令及其工作原理,请打开命令提示符窗口,在其中执行以下命令,并仔细阅读每个命令显示的所有帮助页面。

  • call /?... 还解释了%~dp0... 参数 0 的驱动器和路径,它是始终以反斜杠结尾的批处理文件路径。
  • del /?
  • dir /?
  • echo /?
  • endlocal /?
  • findstr /?
  • for /?
  • goto /?
  • if /?
  • rd /?
  • setlocal /?

阅读有关使用命令重定向运算符2>nul的 Microsoft 文档,了解和的说明|当 Windows 命令解释器在执行命令FOR之前处理命令行时,重定向运算符>|必须^在 FOR命令行上使用脱字符进行转义以解释为文字字符,该命令在后台启动的单独命令进程中执行嵌入式命令行作为附加参数附加的嵌入式命令行。dirfindstr%ComSpec% /c


推荐阅读