Buddy
Buddy

Reputation: 43

How to delete the oldest file in a folder?

I am writing a batch script to backup files and want to include logic that deletes the oldest file in the folder if the number of backups ever exceeds a certain number set by a variable. Pretty new to batch and my current code deletes all files once it exceeds the number.

Any ideas how to do this?

SET Count=0
FOR %%A IN ("%SNAPSHOTNAME%*.*") DO SET /A Count += 1
IF %Count% gtr %NumberOfBackups% FOR %%A IN ("%SNAPSHOTNAME%_PBCS_Test_*.*") DO del "%%A"

Upvotes: 3

Views: 5229

Answers (3)

Mofi
Mofi

Reputation: 49086

I suggest the following single command line for this task:

for /F "skip=%NumberOfBackups% eol=| delims=" %%I in ('dir "%SNAPSHOTNAME%_PBCS_Test_*.*" /A-D-H /B /O-D 2^>nul') do del "%%I"

FOR executes in a separate command process started with cmd.exe /C in background the command line:

dir "%SNAPSHOTNAME%_PBCS_Test_*.*" /A-D-H /B /O-D 2>nul

DIR outputs to handle STDOUT line by line

  • just non-hidden files because of /A-D-H (not attribute directory or hidden)
  • in bare format because of /B which means file name only
  • ordered by last modification (write) time with newest file first and oldest file last.

An error message output by DIR to handle STDERR is suppressed by redirecting it to device NUL with 2>nul.

Read also the Microsoft article about Using Command Redirection Operators for an explanation of 2>nul. The redirection operator > must be escaped with caret character ^ on FOR command line to be interpreted as literal character when Windows command interpreter processes this command line before executing command FOR which executes the embedded dir command line with using a separate command process started in background.

FOR captures this output and processes it line by line according to the options specified in the double quoted string with ignoring empty lines which do not exist in this output of DIR.

The first %NumberOfBackups% lines are skipped by FOR which means the newest %NumberOfBackups% are always kept in current directory.

FOR by default ignores also lines starting with a semicolon because of ; is the default for end of line character. For that reason eol=| is used to change end of line character to vertical bar which is not possible in a file or folder name and so it is impossible that a file name output by DIR starts with |.

FOR by default splits a line into substrings using normal space and horizontal tab character as string delimiters and assigns just first space/tab separated string to loop variable I. This string splitting behavior can be disabled by specifying an empty list of delimiters with delims= at end of the options string to get the entire line (= file name) assigned to the loop variable I.

So DIR outputs the names all non-hidden files matching pattern "%SNAPSHOTNAME%_PBCS_Test_*.*" line by line with newest file first and oldest file last and FOR ignores the first/newest %NumberOfBackups% files and deletes all other older files.

FOR does nothing if DIR outputs less or exactly %NumberOfBackups% file names.

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.

  • del /?
  • dir /?
  • for /?

Note: This is nearly the same answer as written by Squashman, but with full explanation how it works.

Upvotes: 5

Squashman
Squashman

Reputation: 14290

If you change to using a FOR /F command with the SKIP option, you can get rid of the IF comparison.

set "NumberOfBackups=6"
FOR /F "SKIP=%NumberOfBackups% DELIMS=" %%G IN ('DIR /A-D /B /O-D "%SNAPSHOTNAME%_PBCS_Test_*.*"') DO DEL "%%G"

Upvotes: 2

JMichael
JMichael

Reputation: 66

Your second for loop has no sort and no break condition so as mentioned by you it will delete all files.

A dir command can sort the files so instead of taking the for over all files take a for over the sorted output of an dir command. Option /OD will sort for file timestamp.

To let for loop handle the output use for /f. The break condition is to only delete the first (in this case the oldest) file and than jump out the for loop.

IF %Count% gtr %NumberOfBackups% for /f "delims=" %%f in ('dir /B /OD "%SNAPSHOTNAME%_PBCS_Test_*.*"') do del "%%f" & goto :gotIt
:gotIt

Upvotes: 1

Related Questions