简体   繁体   中英

Batch - delete all folders in a folder except those listed in a text file

The aim is to delete all folders (and their sub-folders) except those folders whose names are listed in a text file.

The text file is "F:\\Documents\\Batch\\my folders.txt" and the content is

ABC
DEF

The folders to be deleted are in "F:\\Documents\\Batch\\Practice folder" . It has the following folders in it: ABC , DEF , GHI and JKL .

After running my batch file, only ABC and DEF should remain and all other folder ( GHI , JKL ) should be deleted

Here is what I've tried:

@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

Please help me find a more effective and/or shorter way to do this.

EDIT 1: That code deletes all the folders that match the names in the LISTFILES . But when I do any of:

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

with or without /i (ie if /i ), all folders are delete regardless. So, I tried this and it work

@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

for /d %%G in (*) do as posted in question processes each non hidden subdirectory in current directory whereby loop variable G contains on each loop run the name of a subdirectory without path. Subdirectories with hidden attribute set are ignored by FOR .

And because of enabled delayed environment variable expansion the FOR loop in question does not work for directory names containing one or more exclamation marks. %%G is expanded to current directory name and when this name contains ! , the exclamation mark is interpreted as begin or end of an environment variable name. So everything between two exclamation marks is replaced by current value of the environment variable with name being the string between the two exclamation marks, or more likely with nothing in case of no environment variable exists with that name. A single (remaining) exclamation mark is removed from the directory name. After this additional preprocessing caused by enabled delayed expansion, the (remaining) directory name is really processed further by the appropriate command like IF and RD fails to delete the manipulated directory or deletes the wrong directory.

A batch file for this task working also for hidden subdirectories and directories with one or more exclamation mark in name is:

@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

This batch file can be optimized to a single line too.

@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 outputs to handle STDOUT because of /AD (attribute directory) the list of subdirectories in directory F:\\Documents\\Batch\\Practice folder in bare format because of /B which means just directory name without path. DIR outputs with these options also subdirectories with hidden attribute set.

For the given example the output list is:

ABC
DEF
GHI
JKL

DIR outputs an error message to handle STDERR if it can't find any subdirectory in specified directory or the specified directory does not exist at all that it can't find the specified file instead of directory. This possible and misleading error message is suppressed by redirecting it with 2>nul to device NUL .

The list of subdirectories output by DIR to STDOUT is redirected with | to handle STDIN of next command FINDSTR .

FINDSTR searches in the list of subdirectories read from STDIN

  • case-insensitive because of /I
  • literally because of /L
  • for entire lines because of /X
  • for any string listed in file specified with /G:"..."
  • and outputs to STDOUT all lines NOT matching any search string in list file because of /V (inVerted result).

The output of FINDSTR for the given example is:

GHI
JKL

The entire command line with DIR and FINDSTR is executed by FOR in a background command process started with cmd.exe /C . FOR captures everything output in this command process to STDOUT and processes it next line by line.

The redirection operators | and > must be escaped here with caret character ^ to be interpreted first as literal characters when Windows command interpreter parses the entire FOR command line. Otherwise Windows command interpreter would exit batch processing on FOR command line because of misplaced redirection operators for command FOR .

So FOR finally executes in background without displaying a window:

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"

The loop variable I contains on each loop run a directory name without path found in F:\\Documents\\Batch\\Practice folder and not listed in list file F:\\Documents\\Batch\\my folders.txt . The executed command RD deletes quietly ( /Q ) this directory with all its subdirectories ( /S ).

For understanding the used commands and how they work, open a command prompt window, execute there the following commands, and read entirely all help pages displayed for each command very carefully.

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

Read also the Microsoft article about Using Command Redirection Operators . And the answer on Why is no string output with 'echo %var%' after using 'set var = text' on command line? explains why it is recommended to use set "variable=value" instead of set variable="value" because the position of first " makes a big difference in interpretation by Windows command interpreter.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM