Delete files in a folder but keep the last generated file - batch-file

I need to delete files in an specific folder with a batch script, however, I need to keep the last file generated. Our server has an IIS folder that keeps generating logs, and we need to keep always the last one, but delete the older ones.
Currently we have this script that deletes all the files in an specific folder (in this case, all the files inside C:\Temp):
del /q "C:\Temp\*"
FOR /D %%p IN ("C:\Temp\*.*") DO rmdir "%%p" /s /q
How could we edit that code to keep the last file generated in the folder?
Thank you in advance for your help.

This batch file offers one solution:
#echo off
set "SourceFolder=C:\Temp"
for /F "skip=1 delims=" %%I in ('dir "%SourceFolder%\*" /A-D /B /O-D 2^>nul') do del "%SourceFolder%\%%I"
set "SourceFolder="
The command DIR outputs a list of just file names because of the options /A-D (directory entries with directory attribute not set) and /B (bare format) ordered reverse by last modification date because of /O-D which means the name of the newest modified file is output first.
An error message output by DIR if the specified folder does not contain any file is suppressed by redirecting the error message written to handle STDERR to device NUL using 2>nul. The redirection operator > must be escaped here with caret character ^ to be interpreted as literal character on processing the entire FOR command line by Windows command interpreter. Later FOR executes in a separate command process in background the command dir "%SourceFolder%\*" /A-D /B /O-D 2>nul and captures the output written to STDOUT.
FOR option skip=1 results in skipping first line of captured output which means ignoring the file name of newest modified file.
FOR option delims= disables the default splitting up of the captured lines into space/tab separated strings as every entire file name should be assigned to loop variable I for usage by command executed by FOR.
DEL deletes the file if that is possible at all.
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 /?
echo /?
for /?
set /?
Read also the Microsoft article about Using Command Redirection Operators.

Related

How to find and select newest file in a directory and restore with SQLRestore?

I want to make a batch or cmd file to automatically select the latest file in the directory D:\Romexis_Bilder\romexis_SQL_Backup. These are ZIP SQL backup files that are generated two times daily in the format yymmddhhmm.zip, e.g Romexis_db201805271200.zip on a server running Windows 2016 Server.
The latest added file to the directory (result of FOR /F) should then be used in SQL RESTORE (backup and ftp program Windows).
The idea was to use the FOR command
My draft:
Go into the directory:
pushd "D:\Romexis_Bilder\romexis_SQL_Backup"
Find the latest file. (I don't really know how to set the parameters here.)
for /f "tokens=*" %% in ('dir /D:\Romexis_Bilder\romexis_SQL_Backup /od') do set newest=%%D:\Romexis_Bilder\romexis_SQL_Backup
The result of FOR should be used in *.zip
cd C:\Program Files (x86)\Pranas.NET\SQLBackupAndFTP\
SqlRestore D:\Romexis_Bilder\romexis_SQL_Backup\*.zip -db Romexis_db -srv .\ROMEXIS -pwd password disconnect Romexis_db
I stuck with FOR, but don't know if there would also be another possibility.
I don't know if the last command line in question is really correct. I have some doubts output this line.
But this code can be used to get the name of the newest *.zip file according to last modification date without path.
#echo off
set "BackupFolder=D:\Romexis_Bilder\romexis_SQL_Backup"
for /F "eol=| delims=" %%I in ('dir "%BackupFolder%\Romexis_db*.zip" /A-D-H /B /O-D /TW 2^>nul') do set "NewestFile=%%I" & goto DatabaseRestore
echo ERROR: Could not find any *.zip backup file in folder:
echo "%BackupFolder%"
echo/
pause
goto :EOF
:DatabaseRestore
cd /D "%ProgramFiles(x86)%\Pranas.NET\SQLBackupAndFTP"
SqlRestore.exe "%BackupFolder%\%NewestFile%" -db Romexis_db -srv .\ROMEXIS -pwd password disconnect Romexis_db
echo/
pause
FOR executes in a separate command process started with cmd.exe /C in background the command line:
dir "D:\Romexis_Bilder\romexis_SQL_Backup\*.zip" /A-D-H /B /O-D /TW 2>nul
DIR outputs to handle STDOUT of background command process
only names of non hidden files because of /A-D-H (attribute not directory and not hidden)
in bare format because of /B just the file name with file extension, but without file path
sorted reverse (newest first) by date because of /O-D
using write time (last modification time) because of /TW
in directory D:\Romexis_Bilder\romexis_SQL_Backup matching the pattern Romexis_db*.zip.
I recommend running this command line in a command prompt window to see at least once what DIR outputs.
DIR would output an error message to handle STDERR in case of no *.zip file found or the directory does not exist at all. This error message is suppressed by redirecting it to device 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 the output written to STDOUT and processes the output line by line with ignoring empty lines which do not occur here because of DIR with option /B does not output empty lines.
FOR with option /F would ignore lines starting with a semicolon by default. For that reason end of line character is redefined with eol=| from ; to a vertical bar which file names can't contain. eol=| would not be required in this case because of file name pattern Romexis_dbYYYMMDDhhmm.zip making it unlikely that a file name starts with a semicolon.
FOR with option /F would split up the lines into substrings using space/tab as delimiter and would assign for each line only first space/tab delimited string to specified loop variable I. This line splitting behavior is disabled by specifying an empty list of delimiters with delims=. delims= would not be required in this case because of file name pattern Romexis_dbYYYMMDDhhmm.zip making it unlikely that a file name contains a space character.
The name of the file output first by DIR which is the newest ZIP file in specified directory is assigned to environment variable NewestFile. And next the FOR loop is exited with a jump to label DatabaseRestore as all other file names output by DIR are of no interest for this task.
The command lines below the FOR command line are executed only if there is no *.zip file in specified directory which report this unexpected error case.
It would be also possible to use the DIR command line below in batch file because of file name pattern Romexis_dbYYYMMDDhhmm.zip:
dir "%BackupFolder%\Romexis_db*.zip" /A-D-H /B /O-N 2^>nul
The same command line for execution from within a command prompt window:
dir "D:\Romexis_Bilder\romexis_SQL_Backup\*.zip" /A-D-H /B /O-N 2>nul
The order of the file names in output is here reverse by name which results in printing first the Romexis_db*.zip with newest date/time in file name thanks to date/time format YYYMMDDhhmm.
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.
cd /?
dir /?
echo /?
for /?
goto /?
pause /?
set /?
See also:
Where does GOTO :EOF return to?
Single line with multiple commands using Windows batch file
#Mofi
Thanks you for all your work it helped a lot!
As you advised I used each command in command prompt first to see the outputs (adapted batch %%I to cmd %I and vice versa)
I'm now able to find the newest file in D:\Romexis_Bilder\romexis_SQL_Backup the result is processed an taken as variable into the restore of the database which is done with One-Click SQL Restore https://sqlbackupandftp.com/restore
I did some modification in syntax of your commands O:D since „- „ excludes, removed attribute /TW because it was only listing backups from 2017.
#echo off
set "BackupFolder=D:\Romexis_Bilder\romexis_SQL_Backup"
for /F "eol=| delims=" %I in ('dir "%BackupFolder%\Romexis_db*.zip" /A-D-H /B /O:D 2^>nul') do set "NewestFile=%I" & goto DatabaseRestore
echo ERROR: Could not find any *.zip backup file in folder:
echo "%BackupFolder%"
echo/
pause
goto :EOF
:DatabaseRestore
cd /D "%ProgramFiles(x86)%\Pranas.NET\SQLBackupAndFTP"
SqlRestore.exe "%BackupFolder%\%NewestFile%" -db Romexis_db -srv .\ROMEXIS -pwd password
echo/
pause
Maybe the ^ in 'dir "%BackupFolder%\Romexis_db*.zip" /A-D-H /B /O:D 2^>nul' is not correct in CMD but didn‘t seem affect the result.
It was really advance! Now the GUI of One-Click SQL Restore opens with the newest *zip . The only thing that I still need to get out, is the syntax in command prompt for the restore, now i still need to click on the restore button of the GUI. Or try it over Microsoft Visual Studio SQL or command line tool.
#MOFI no modifications are made to files from 2017 or other files at all, files are not overwritten or modified later, a new file is always created by the back up program 2 times a day with the naming romexis_dbYYYMMDDhhmm.ziptwo times a day. Will try /O-N
THANKS a lot fo you input

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.
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.

Batch file to copy files with unique timestamps measured to the minute

Like the question says, I have a folder full of photos but many of the photos are duplicates. The pictures are in groups of 10-15 in the same minute and then the next group has a timestamp of a few minutes later. I want to copy 1 photo from each group to a new folder. I found some code that I think might mostly work, but the command copies and excludes based on file name, not timestamp. Any help would be greatly appreciated.
For %%F In ("G:\Bad\*.*") Do If Not Exist "G:\Good\%%~nxF" Copy "%%F" "C:\Good\%%~nxF"
This file copying task could be done with following batch file:
#echo off
setlocal EnableExtensions EnableDelayedExpansion
set "LastFileTime="
for %%I in ("C:\Path To\Source Folder\*") do (
if "%%~tI" NEQ "!LastFileTime!" (
set "LastFileTime=%%~tI"
copy /B /Y "%%I" "C:\Path To\Destination Folder\" >nul
)
)
endlocal
Command FOR runs for each non hidden file in specified source folder the IF comparison which compares case-sensitive last modification time of current file with the file time last assigned to environment variable LastFileTime using delayed expansion as required here because the environment variable value is changed and referenced in same command block.
On a difference the last modification file time of current file is assigned to the environment variable and the file is copied to destination folder which must already exist on running this batch file.
Note: On an NTFS drive the list of file names processed by FOR is sorted by file name and not by file time. On a FAT16, FAT32 and ExFAT drive the list of file names is not sorted at all. This means this simple approach works only reliable on an NTFS drive with all files with same last modification date have nearly the same file name.
So it would be better to process the list of files sorted by last modification time for example using following code:
#echo off
setlocal EnableExtensions EnableDelayedExpansion
set "LastFileTime="
cd /D "C:\Path To\Source Folder"
for /F %%I in ('dir * /A-D /B /OD /TW 2^>nul') do (
if "%%~tI" NEQ "!LastFileTime!" (
set "LastFileTime=%%~tI"
copy /B /Y "%%I" "C:\Path To\Destination Folder\"
)
)
endlocal
DIR outputs all directory entries
matching the wildcard pattern * (*.* is interpreted as * by Windows),
not having attribute directory set because of /A-D which means only the names of files including hidden and system files,
in bare format because of /B which means just file name without any additional information,
with the output list ordered by date/time because of /OD with oldest first and newest last
whereby the date/time to use for sort is the last modification (write) date because of /TW which would not be necessary as the last modification date is the default.
The help output by running dir /? in a command prompt window explains also all these options. And running just dir * and next dir * /A-D /B /OD /TW in a command prompt window in a directory with files and comparing the two output lists makes the difference very clear.
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.
cd /?
copy /?
dir /?
echo /?
endlocal /?
for /?
if /?
set /?
setlocal /?
Read also the Microsoft article about Using Command Redirection Operators to understand >nul used here to suppress the message about number of copied files by redirecting it to device NUL.
2>nul suppresses the error message output by DIR if there is no file in source directory by redirecting the error message output to handle STDERR to device NUL whereby the redirection operator > needs to be escaped here with caret character ^ for being parsed as literal character on parsing the FOR command line by Windows command interpreter and as redirection operator later on execution of DIR command line in a separate command process.

Getting the attributes of the last modified file in a directory written in a file

I am in the need of a batch script that checks a drive (D:) for the 'last modified' attribute of *.czi files (Carl Zeiss image files) and append the data to a file on another drive. I have tried solutions with the following line:
FOR /F "delims=" %%I IN ('DIR %source%*.czi /A:-D /O:-D /T:W /B') DO COPY "%%I" > %target%
that does give me the last file, but it copies the entire file which is not that smart since they can be big. As a biologist I will spare you for my desperate attempts that did not work (spent 4-5 hours). I figure this can be done dead easily, that is if you know how... Any good suggestions? Any reply will be appreciated! Thanks in advance.
Let's assume just the last modified file time from newest file is wanted from all *.czi files in directory C:\Temp containing for example:
30.01.2017 08:13 First Listed.czi
28.01.2017 21:26 Oldest Image.czi
03.02.2017 17:13 Newest Image.czi
The batch code for this task could be:
#echo off
set "Source=C:\Temp\"
set "Target=%Source%List.txt"
for /F "delims=" %%I in ('dir "%Source%*.czi" /A:-D /B /O:-D /T:W 2^>nul') do (
echo File "%%I" last modified on %%~tI>>"%Target%"
goto AfterLoop
)
:AfterLoop
The command DIR searches in for *.czi files in directory C:\Temp and outputs the list sorted by last modification time in reverse order from newest to oldest.
In case of no *.czi file could be found, command DIR would output an error message to handle STDERR. This output message is redirected with 2>nul to device NUL to suppress it whereby the redirection operator > must be escaped here with ^ to be interpreted as redirection operator on execution of DIR command line and not already on parsing FOR command line.
%%I references the name of the file as output by DIR and %%~tI references the last modification date of the file. The help of command FOR output by running in a command prompt window for /? explains those modifiers.
The loop is exited after first output of the text redirected to the target file on which the line is appended if it is already existing because of using >> instead of just >.
For the example files list the following line is appended to C:\Temp\List.txt:
File "Newest Image.czi" last modified on 03.02.2017 17:13
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 /?
for /?
goto /?
set /?
See also the Microsoft article Using command redirection operators.
Your question is unclear, so let me try to rephrase it:
I think you want to find the Most Recently Modified file with a .CZI extension, and copy only that newest file to some target destination.
To list all .CZI files in all subdirectories, sorted by newest-file first:
(for /f %a in ('dir *.CZI /s /b') do #echo %~ta %~fa) | sort
If the first line of this output is the file that you want, then all you need to do is copy that one file to your target.
(and please, take the time to write detailed and clear questions so we can provide good answers)

Get newest file in directory with specific extension

The batch command below will get me the newest file in a folder, however I'm only looking for files with a specific extension. Can anyone explain how to specify the extension (i.e. .jpg)
FOR /F "delims=|" %%I IN ('DIR "C:\Jenkins\Releases\C9metro" /B /O:D') DO SET NewestFile=%%I
I suggest to use the following lines:
FOR /F "eol=| delims=" %%I IN ('DIR "C:\Jenkins\Releases\C9metro\*.jpg" /A-D /B /O-D /TW 2^>nul') DO (
SET "NewestFile=%%I"
GOTO FoundFile
)
ECHO No *.jpg file found!
GOTO :EOF
:FoundFile
ECHO Newest *.jpg file is: "%NewestFile%"
The FOR loop can be also optimized to a single command line:
FOR /F "eol=| delims=" %%I IN ('DIR "C:\Jenkins\Releases\C9metro\*.jpg" /A-D /B /O-D /TW 2^>nul') DO SET "NewestFile=%%I" & GOTO FoundFile
ECHO No *.jpg file found!
GOTO :EOF
:FoundFile
ECHO Newest *.jpg file is: "%NewestFile%"
FOR starts in background one more cmd.exe with option /c and the command line within ' appended as additional arguments. There is executed in this case in background with Windows installed into C:\Windows:
C:\Windows\System32\cmd.exe /c DIR "C:\Jenkins\Releases\C9metro\*.jpg" /A-D /B /O-D /TW 2>nul
The internal command DIR searches now for file system entries in the specified directory matching the wildcard pattern *.jpg with following additional restrictions.
The parameter /A-D makes sure ignoring subdirectories which unusually end by chance also with the string .jpg.
The parameter /B turns on bare output format. In this case are output just the file names without path by command DIR never enclosed in " even on containing a space or one of these characters &()[]{}^=;!'+,`~ which require the file name string to be enclosed in " on further processing it by cmd.exe on other command lines.
The parameter /O-D results in getting output by DIR the found file names listed by date in reverse order from newest to oldest. In other words the file name of the newest file is output first and the file name of the oldest file is output last.
And parameter /TW makes sure the last modification time (write access) is used for ordering the found file names of the JPEG files in date order and not the creation or the last access time.
There could be no file name matching the wildcard pattern *.jpg in long or short 8.3 name in which case DIR outputs an error message to standard error stream STDERR of the background command process. cmd.exe processing the batch file would redirect that error output to its own standard error stream. That would result in displaying the error message in the console window not really useful for a user of the batch file. The usage of 2>nul instructs cmd.exe started in background to redirect the error message to device NUL to suppress it.
Read the Microsoft documentation 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 respectively cmd.exe processing the batch file captures all output written to standard output stream of in background started cmd.exe and processes it line by line after started cmd.exe closed itself after finishing executing the command DIR.
FOR on using option /F ignores always empty lines which is no problem here as DIR with the used options does not output empty lines.
FOR would next split up the lines into substrings using horizontal tab and normal space as string delimiters, would look next if first tab/space separated string begins with a semicolon in which case it would also ignore the entire line for further processing, and would otherwise assign just the first tab/space separated string to the specified loop variable I before running the commands in body of FOR.
The default line splitting behavior is not wanted as JPEG file names can contain one or more spaces. The usage of the option delims= defines an empty list of delimiters which turns off the line splitting behavior.
It is very unusual but nevertheless possible that a JPEG file name begins with ; (semicolon). Such a file name should not be ignored by FOR. The option eol=| defines a vertical bar as end of line character which no file name can contain ever. Microsoft lists the characters not allowed in a file name on Windows file systems in the documentation about Naming Files, Paths, and Namespaces.
So, the first file name output by DIR being from the newest file is assigned completely to the loop variable I and executed is the command SET to assign this string to the environment variable NewestFile.
The loop is exited on first found file matching the wildcard pattern *.jpg is assigned to the environment variable. That makes this method faster than letting DIR output the file names from oldest to first and assigning all file names one after the other to the variable NewestFile up to last found file which would be the newest file.
There is an error message output on DIR could not find any file and so FOR could not assign any file name string to the loop variable I and run once the commands SET and GOTO. Then the batch file processing is exited in this case as described in detail by Where does GOTO :EOF return to?
To understand the commands used and how they work, open a command prompt window, execute there the following commands, and read the displayed help pages for each command, entirely and carefully.
dir /?
echo /?
endlocal /?
for /?
goto /?
set /?
setlocal /?
See also:
Why is no string output with 'echo %var%' after using 'set var = text' on command line?
Single line with multiple commands using Windows batch file explaining the unconditional command operator & as used in the second example.
It's early... figured this one out:
'DIR "C:\Jenkins\Releases\C9metro\*.jpg"

Resources