aidangallagher4
aidangallagher4

Reputation: 179

How to use a FOR loop to act on files which don't fulfil a condition?

I'm making a simple batch script to process a large set of files and delete all I don't want. I want about 10% of the files and they all have certain tags in their names, lets say they contain apple, orange or pear. As there are so many files I want deleted, it would be quite time consuming to construct a FOR loop such as:

@echo off
pause
for /R %%i in ([the list of names of the files I don't want]) do del %%i
pause

So I was wondering if it is possible to code it such that it deletes all files which don't have names containing apple, orange or pear?

In other words all files should be deleted not containing in its name one of those 3 words.

I'm using a FOR loop because the files are nested within lots of subdirectories and I would like to preserve this structure after the unwanted files have been deleted.

Upvotes: 1

Views: 68

Answers (1)

Mofi
Mofi

Reputation: 49097

You can use this batch file containing (more or less) just one command line:

@echo off
for /F "delims=" %%I in ('dir * /A-D /B /S 2^>nul ^| %SystemRoot%\System32\findstr.exe /I /R /V /C:"apple[^\\]*$" /C:"orange[^\\]*$" /C:"pear[^\\]*$"') do ECHO del "%%I"

This batch code does not really delete files because of command ECHO before del at end of the command line. Run this batch file from within a command prompt window with current directory being the root of the directory tree on which to delete unwanted files and verify the output. Then remove ECHO and run the batch file once again.

The command DIR searches because of /S in current directory and all subdirectories only for files because of /A-D (not directory attribute) matching the wildcard pattern * with output in bare format because of /B which means the output contains just the names of all found files with full path.

DIR outputs an error message to handle STDERR if it can't find any file. This error message is suppressed by redirecting it to device NUL with 2>nul. The redirection operator > must be escaped here with caret character ^ to be first interpreted as literal character on parsing the FOR command line by Windows command interpreter.

The output of DIR to handle STDOUT is piped with | to standard console application FINDSTR which searches in all lines case-insensitive because of /I for the regular expression strings because of /R specified with /C:. The redirection operator | must be escaped here also with ^.

An OR expression is not supported by FINDSTR like it is by other applications with regular expression support. But it is possible to specify multiple search strings as done here which are all applied on each line of the text to process one after the other until a positive match occurs or there is no more search string. That is a classic OR.

The regular expression word[^\\]*$ means:

  • word ... There must be found word (case-insensitive).
  • [^\\]* ... Find 0 or more characters NOT being a backslash.
  • $ ... The matching string must be found at end of line.

The regular expression is used to get a positive match only for lines on which the file name contains either apple OR orange OR pear, but NOT the file path.

But there is one more FINDSTR option: /V. This option inverts the result output to handle STDOUT. So output are the lines on which none of the 3 regular expressions produce a positive match.

The command FOR processes each line output by FINDSTR used as negative filter for output of DIR and runs for each line the command DEL respectively ECHO without splitting the line up into space/tab separated strings because of delims=.

And that's it.

It is necessary to prevent the batch file from deletion if being stored in the directory tree processed by command DIR. This can be achieved most easily with setting read-only attribute on batch file as command DEL does not delete files with read-only attribute set.

Example:

@echo off
rem Prevent batch file from deletion by setting read-only attribute on batch file.
%SystemRoot%\System32\attrib.exe +r "%~f0"

for /F "delims=" %%I in ('dir * /A-D /B /S 2^>nul ^| %SystemRoot%\System32\findstr.exe /I /R /V /C:"apple[^\\]*$" /C:"orange[^\\]*$" /C:"pear[^\\]*$"') do del "%%I"

rem It is safe to remove read-only attribute from batch file.
%SystemRoot%\System32\attrib.exe -r "%~f0"

The batch code above has no ECHO before command del and therefore really deletes files on execution.

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.

  • attrib /?
  • del /?
  • dir /?
  • echo /?
  • findstr /?
  • for /?
  • rem /?

Read also the Microsoft article about Using Command Redirection Operators for an explanation of | and 2>nul.

Upvotes: 1

Related Questions