【问题标题】:Batch - delete all folders in a folder except those listed in a text file批量 - 删除文件夹中的所有文件夹,文本文件中列出的文件夹除外
【发布时间】:2017-10-26 18:40:08
【问题描述】:

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

文本文件为"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

【问题讨论】:

  • 每个文件夹是否在文本文件中单独列出?
  • 是的@Squashman,
  • 使用 find 或 findstr 查看文件夹名称是否在您的文件列表中。

标签: batch-file


【解决方案1】:

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

由于启用了延迟的环境变量扩展,有问题的 FOR 循环不适用于包含一个或多个感叹号的目录名称。 %%G 扩展为当前目录名称,当此名称包含 ! 时,感叹号被解释为环境变量名称的开头或结尾。因此,两个感叹号之间的所有内容都将替换为环境变量的当前值,其中名称是两个感叹号之间的字符串,或者如果没有具有该名称的环境变量,则更可能没有任何内容。从目录名称中删除一个(剩余的)感叹号。在启用延迟扩展导致的附加预处理之后,(剩余的)目录名称实际上由适当的命令(如 IFRD 进行进一步处理)无法删除被操纵的目录或删除错误的目录。

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

@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 中的子目录列表为裸格式,因为/B 这意味着只是没有路径的目录名称. DIR 带有这些选项的输出也带有隐藏属性集的子目录。

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

ABC
DEF
GHI
JKL

DIR如果在指定目录中找不到任何子目录或指定目录根本不存在则输出错误信息处理STDERR找到指定的文件而不是目录。通过使用 2>nul 将其重定向到设备 NUL 来抑制这种可能且具有误导性的错误消息。

DIR 输出到 STDOUT 的子目录列表被重定向到 | 以处理下一个命令 FINDSTRSTDIN /strong>。

FINDSTR 搜索从 STDIN

读取的子目录列表
  • 不区分大小写,因为/I
  • 字面意思是因为/L
  • 因为/X而导致整行
  • 对于用/G:"..." 指定的文件中列出的任何字符串
  • 并输出到 STDOUT 所有行 NOT 匹配列表文件中的任何搜索字符串,因为 /V(反转结果)。

对于给定示例,FINDSTR 的输出是:

GHI
JKL

DIRFINDSTR 的整个命令行由 FOR 在以cmd.exe /C 开头的后台命令进程中执行。 FOR 将此命令过程中的所有输出捕获到 STDOUT 并逐行处理。

重定向运算符|> 必须在此处使用插入符号^ 进行转义,以便在Windows 命令解释器解析整个FOR 命令行时首先将其解释为文字字符。否则,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 中找到路径,也没有在列表文件F:\Documents\Batch\my folders.txt 中列出。执行的命令 RD 会悄悄删除 (/Q) 该目录及其所有子目录 (/S)。

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

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

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-12-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多