批处理 - 删除文件夹中除文本文件中列出的文件夹之外的所有文件夹

时间:2017-10-26 18:40:09

标签: batch-file

目的是删除所有文件夹(及其子文件夹),但名称在文本文件中列出的文件夹除外。

文本文件为"F:\Documents\Batch\my folders.txt",内容为

ABC
DEF

要删除的文件夹位于"F:\Documents\Batch\Practice folder"。它包含以下文件夹:ABCDEFGHIJKL

运行我的批处理文件后,只应保留ABCDEF,并删除所有其他文件夹(GHIJKL

以下是我尝试的内容:

@echo off

set WORKDIR="F:\Documents\Batch\Practice folder"
set LISTFILES="F:\Documents\Batch\my folders.txt"

pushd %WORKDIR%
for /d  %%G in (*) do (
    for /f "tokens=* usebackq" %%H in (%LISTFILES%) do (
        if %%G==%%H rd /s /q "%%G"
    )
)
popd

请帮助我找到更有效和/或更短的方法。

编辑1: 该代码将删除与LISTFILES中的名称匹配的所有文件夹。但当我做任何一件事时:

if not %%G==%%H rd /s /q "%%G"
if not [%%G]==[%%H] rd /s /q "%%G"
if not "%%G"=="%%H" rd /s /q "%%G"

有或没有/i(即if /i),无论如何都删除所有文件夹。 所以,我试过这个并且它可以工作

@echo off
setlocal enableDelayedExpansion

set WORKDIR="D:\IFX\services\4"
set LISTFILES="D:\IFX\services\files.txt"

set delete=

pushd %WORKDIR%
for /d  %%G in (*) do (
    set delete=1
    for /f "tokens=* usebackq" %%H in (%LISTFILES%) do (
        if /i %%G equ %%H set delete=0
    )
    if !delete!==1 rd /s /q %%G
)
popd

1 个答案:

答案 0 :(得分:1)

发布的

for /d %%G in (*) do处理当前目录中的每个非隐藏子目录,其中循环变量G包含在每个循环上运行没有路径的子目录的名称。 FOR 会忽略具有隐藏属性集的子目录。

由于启用了延迟环境变量扩展,所讨论的 FOR 循环对包含一个或多个感叹号的目录名称不起作用。 %%G扩展为当前目录名称,当此名称包含!时,感叹号将被解释为环境变量名称的开头或结尾。因此,两个感叹号之间的所有内容都被环境变量的当前值替换,其中name是两个感叹号之间的字符串,或者更可能在没有该名称的环境变量的情况下没有任何内容。从目录名称中删除单个(剩余)感叹号。在由启用的延迟扩展引起的额外预处理之后,(其余)目录名称实际上由适当的命令进一步处理,如 IF RD 无法删除被操纵的目录或删除错误的目录。

此任务的批处理文件也适用于名称中包含一个或多个感叹号的隐藏子目录和目录:

@echo off
setlocal EnableExtensions DisableDelayedExpansion
set "WORKDIR=F:\Documents\Batch\Practice folder"
set "LISTFILE=F:\Documents\Batch\my folders.txt"
for /F "eol=| delims=" %%I in ('dir "%WORKDIR%\*" /AD /B 2^>nul ^| %SystemRoot%\System32\findstr.exe /I /L /V /X /G:"%LISTFILE%"') do rd /Q /S "%WORKDIR%\%%I"
endlocal

此批处理文件也可以优化为单行。

@for /F "eol=| delims=" %%I in ('dir "F:\Documents\Batch\Practice folder\*" /AD /B 2^>nul ^| %SystemRoot%\System32\findstr.exe /I /L /V /X /G:"F:\Documents\Batch\my folders.txt"') do @rd /Q /S "F:\Documents\Batch\Practice folder\%%I"

dir "F:\Documents\Batch\Practice folder\*" /AD /B输出处理 STDOUT ,因为/AD(属性目录)目录F:\Documents\Batch\Practice folder中的子目录列表由于{{1}而采用裸格式这意味着只有没有路径的目录名。 DIR 输出这些选项也是隐藏属性设置的子目录。

对于给定的示例,输出列表为:

/B

DIR 输出错误消息以处理 STDERR ,如果它找不到指定目录中的任何子目录或指定的目录根本不存在它不能找到指定的文件而不是目录。通过将ABC DEF GHI JKL 重定向到设备 NUL ,可以抑制这种可能且误导性的错误消息。

DIR 输出到 STDOUT 的子目录列表将被重定向到2>nul以处理下一个命令的 STDIN FINDSTR

FINDSTR 搜索从 STDIN

中读取的子目录列表
    由于|
  • 不区分大小写
  • 字面上是因为/I
  • 由于/L
  • 表示整行
  • 表示使用/X
  • 指定的文件中列出的任何字符串
  • 并输出 STDOUT 所有行 NOT 匹配列表文件中的任何搜索字符串,因为/G:"..."(inVerted结果)。

给定示例的 FINDSTR 输出为:

/V

在以GHI JKL 开头的后台命令进程中, DIR FINDSTR 的整个命令行由 FOR 执行。 FOR 将此命令进程中的所有输出捕获到 STDOUT 并逐行处理。

当Windows命令解释器解析整个 FOR cmd.exe /C和|必须使用符号字符>进行转义,首先解释为文字字符>命令行。否则Windows命令解释程序将退出 FOR 命令行上的批处理,因为命令 FOR 的重定向操作符错位。

所以 FOR 最终在后台执行而不显示窗口:

^

循环变量cmd.exe /C dir "F:\Documents\Batch\Practice folder\*" /AD /B 2>nul | C:\Windows\System32\findstr.exe /I /L /V /X /G:"F:\Documents\Batch\my folders.txt" 在每个循环上运行一个目录名,没有在I中找到的路径,但未在列表文件F:\Documents\Batch\Practice folder中列出。执行的命令 RD 将及其所有子目录(F:\Documents\Batch\my folders.txt)静默删除(/Q)此目录。

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

  • /S
  • dir /?
  • echo /?
  • endlocal /?
  • findstr /?
  • for /?
  • rd /?
  • set /?

另请阅读有关Using Command Redirection Operators的Microsoft文章。 Why is no string output with 'echo %var%' after using 'set var = text' on command line?上的答案解释了为什么建议使用setlocal /?代替set "variable=value",因为第一个set variable="value"的位置会对Windows命令解释器的解释产生很大影响。< / p>