0

Currently, I have to upload a bunch of excel sheets to a network shared folder. Each of these files has the they were created appended at the end of the filename. Then I have to remove the earlier leaving just the latest dated versions.

Basically it looks likes this...

Before:

apples 2019.07.01.xlsx
apples 2019.07.07.xlsx
oranges 2019.07.01.xlsx
bananas 2019.07.01.xlsx

After:

apples 2019.07.07.xlsx
oranges 2019.07.01.xlsx
bananas 2019.07.01.xlsx

I stumbled upon a possible solution, which was to create a to recursively go through the folder and do this. However, I am unsure where to start.

I read this other stackoverflow article, which is pretty close to what I want to do but I am having trouble adjusting it to my needs. Any assistance would be appreciated.

Edit2: this code worked for me:

@(
  SetLocal EnableDelayedExpansion
  ECHO OFF
  SET "_PathToCheck=Y:\T\DT"
  SET "_FileGlob=PLOG - * - ????.??.?? - *.xlsx"
  SET "_CurrentFile="
)

FOR /F "Tokens=1-2* Delims=-" %%A IN ('DIR /A-D /O-N /B "%_PathToCheck%\%_FileGlob%"') DO (
  IF /I "!_CurrentFile!" EQU "%%A-%%B" (
    ECHO.Deleting: "%_PathToCheck%\%%A-%%B-%%C"
    DEL /F /Q "%_PathToCheck%\%%A-%%B-%%C"
  ) ELSE (
    ECHO.
    ECHO.New File Found: "%%A-%%B"
    ECHO.-----------
    ECHO.Retaining: "%_PathToCheck%\%%A-%%B-%%C"
    SET "_CurrentFile=%%A-%%B"
  )
)
Greg Williams
  • 15
  • 1
  • 4
  • 1
    If you post what you have tried that isn't working we can probably point you in the right direction. – mael' Jul 10 '19 at 21:12
  • 1
    Take a read of the code, read the usage information for each of the commands, and start trying it in small sections. To find out how a command is used, enter the command name followed by `/?` at the Command Prompt. When you come across a specific issue, [edit your question](https://stackoverflow.com/posts/56978694/edit) to explain what you've read, tried and what happened when you did. _Your date format is currently unknown because we're unable to determine which is `dd` and which is `MM`_. – Compo Jul 10 '19 at 21:32
  • The example the OP found is doing way more than needed in this scenario, Date conversion is an unnecessary complication when you want to keep the newest N files, instead of Files Newer than X Days Old, in face the User may not even have a file they uploaded in the last Y Years but it's still the newest file, so review of that code will only serve to make the OP struggle to accomplish their goal. – Ben Personick Jul 10 '19 at 22:31
  • What about the file date (last modification or creation)? could this be used as well instead of the (locale-dependent) dates in the file names? – aschipfl Jul 10 '19 at 23:32

2 Answers2

1

You may use the same approach you would use if you do this job by hand: review the file list and every time that a file appear with the same name than the previous one, remove the previous one... Simple! Isn't it? ;)

@echo off
setlocal EnableDelayedExpansion

rem Initialize the "previous name"
set "lastName="
rem Process files in natural order, that is, the same order showed in the question
rem and set %%a to name and %%b to rest: date plus extension
for /F "tokens=1*" %%a in ('dir /B /A:-D /O:N *.xlsx') do (
   rem If previous name is not the same as current one
   if "!lastName!" neq "%%a" (
      rem Just update previous name and date
      set "lastName=%%a"
      set "lastDate=%%b"
   ) else (
      rem Remove the previous file
      ECHO del "!lastName! !lastDate!"
      rem and update the previous date
      set "lastDate=%%b"
   )
)

This solution assumes that the name and the date parts are separated by exactly one space...

EDIT: New method added, after several confusing changes made by the OP

@echo off
setlocal EnableDelayedExpansion

set "lastName="
for /F "delims=" %%a in ('dir /B /A:-D /O:N *.xlsx') do (
   set "currName="
   set "currFile="
   for %%b in (%%~Na) do (
      set "part=%%b"
      set "currFile=!currFile! !part!"
      if "!part:.=!" equ "!part!" set "currName=!currName! !part!"
   )
   if "!lastName!" neq "!currName!" (
      set "lastName=!currName!"
      set "lastFile=!currFile!"
   ) else (
      ECHO del "!lastFile:~1!.xlsx"
      set "lastFile=!currFile!"
   )
)

Example of input files:

apples 2019.07.01.xlsx
apples 2019.07.07.xlsx
oranges 2019.07.01.xlsx
bananas 2019.07.01.xlsx
apples 2019.07.01 proof1.xlsx
apples 2019.07.07 proof1.xlsx
PLOG - Organic Valley - 2019.07.01 - (DAI) OG Cream Cheese.xlsx
PLOG - Organic Valley - 2019.07.07 - (DAI) OG Cream Cheese.xlsx
PLOG - Organic Valley - 2019.07.10 - (DAI) OG Cream Cheese.xlsx

Output:

del "apples 2019.07.01.xlsx"
del "apples 2019.07.01 proof1.xlsx"
del "PLOG - Organic Valley - 2019.07.01 - (DAI) OG Cream Cheese.xlsx"
del "PLOG - Organic Valley - 2019.07.07 - (DAI) OG Cream Cheese.xlsx"
Aacini
  • 65,180
  • 12
  • 72
  • 108
  • This also assumes: There will never be any spaces in the file names other than the final, and that the date format is YYYY.MM.DD, it does not take into account what the name format is it may be YYYY.MM.DD or YYYY.DD.MM. – Ben Personick Jul 11 '19 at 03:54
  • @BenPersonick As your own answer this one is based an assumptions where OP left out details (aside from own code tries). Here ***I*** prefer Aacinis less verbose answer which matches the presented case ;-) –  Jul 11 '19 at 09:25
  • @Lotpings Ie, I was specifically just addressing the statement ` "This solution assumes that the name and the date parts are separated by exactly one space..."` – Ben Personick Jul 11 '19 at 11:05
  • i love the simplicity of this but while I am pretty fluent in VBA, I'm not sure how this code reads; would you be able to explain it? Also, what if the date is in the middle of the filename; is it able to handle that? EX: apples 07.01.2019 proof1.xlsx – Greg Williams Jul 11 '19 at 13:52
  • @GregWilliams , this is the original form of my first solution, just with the assumption that there will not be any spaced which I didn't want to assume so as I had asked Qs to clarify the spacing and the date format, essentially the explanation I gave there yesterday still hold as the logic is the same for the flow of the script. – Ben Personick Jul 11 '19 at 14:29
  • I added some explanations to the code. Please note that this code just _display_ the `del` command. You need to remove the `ECHO` part in order to really delete the files... If you have any doubt on how the method works, just do a test or post a more detailed question... For example, this method should work on this file: `apples 07.01.2019 proof1.xlsx` as long as the _name_ is just `apples`; otherwise, the code requires several modifications... – Aacini Jul 11 '19 at 14:44
  • `what if the date is in the middle of the filename; is it able to handle that? EX: apples 07.01.2019 proof1.xlsx` Don't know how I missed this before, but no. This script will not be able to handle that for multiple reasons. My scripts are close to handling this, but they assumed your original format was correct, although we have all inquired as to whateher it is, and if our assumptions are correct but I haven;t seen any clarifying answers from you, you may have missed our Queries on this? We need to have an exact repeatable pattern that IDs duplicate (name) vs unique (date etc) parts – Ben Personick Jul 11 '19 at 14:53
  • @BenPersonick: This is interesting... Of course that this script will handle the `apples 07.01.2019 proof1.xlsx` format _as long as the "name" is just the first part before the date_. Did you completed a test? **`;)`** – Aacini Jul 11 '19 at 15:06
  • @Aacini Your approach is exactly how I initially considered approaching the answer, however I discarded it in my first draft, as it could only work if we could assume there was only ever one space in the name prior to the date, but I suspected correctly that this was not the case, so when I initially wrote it I modified the method used to better approximate that, however, there are further caveats which break both of our methods as the OP gave us misinformation on what the format actually is. – Ben Personick Jul 11 '19 at 15:26
  • @GregWilliams: Uff... Too many confusing changes... **`:/`** See my new method... – Aacini Jul 11 '19 at 16:03
  • Let us [continue this discussion in chat](https://chat.stackoverflow.com/rooms/196331/discussion-between-ben-personick-and-aacini). – Ben Personick Jul 11 '19 at 16:31
0

Here is the newest version for you Greg.

Although originally I and a couple of others wrote versions which would work for date modified using a different logic (create variables for all of the files' names then sort them again, or do sets of compares) I realized we could still accomplish the goal in a single loop and without needing so many temp variables and without having to have more complex logic in that scenario and this one, so I took a few minutes and created that version.

Essentially we just need to define a variable with the File's name that has already been found, since we know they are ordered correctly date-wise, and only need to worry about removing the duplicate named files.

To do so we can use SEt or IF DEFINED, I prefer IF DEFINED here since I can use regular IF ( ) THEN ( ) ELSE ( ) logic as already defined in the script. (Note the items in Italic here are not terms that can be used in a CMD script, but I am writing them to clarify the normal logic of the IF construct)

We could use SET "[Variable Name]" instead, and test if success or failure using || or &&, but that would be more re-write and unnecessary here.


@(
  SetLocal EnableDelayedExpansion
  ECHO OFF
  SET "_PathToCheck=C:\T\DT"
  SET "_FileGlob=PLOG - * - ????.??.?? - *.xlsx"
  SET "_CurrentFile="
  SET "_MatchList="
)

FOR /F "Tokens=1-3* Delims=-" %%A IN ('
  DIR /A-D /O-N /B "%_PathToCheck%\%_FileGlob%"
') DO (
  SET "_CurrentFile=%%A-%%B-%%D"
  SET "_MatchList=!_CurrentFile: =_!"
  IF DEFINED _MatchList_!_MatchList! (
    ECHO.Deleting: "%_PathToCheck%\%%A-%%B-%%C-%%D"
    DEL /F /Q "%_PathToCheck%\%%A-%%B-%%C-%%D"
  ) ELSE (
    ECHO.
    ECHO.New File Found: "!_MatchList!" Date-Stamp: %%C
    ECHO.-----------
    ECHO.Retaining: "%_PathToCheck%\%%A-%%B-%%C-%%D"
    SET "_MatchList_!_MatchList!=%%A-%%B-%%D"
  )
)

The previous version which conformed to the standards for only the left side of the file name being unique.

@(
  SetLocal EnableDelayedExpansion
  ECHO OFF
  SET "_PathToCheck=Y:\T\DT"
  SET "_FileGlob=PLOG - * - ????.??.?? - *.xlsx"
  SET "_CurrentFile="
)

FOR /F "Tokens=1-2* Delims=-" %%A IN ('
  DIR /A-D /O-N /B "%_PathToCheck%\%_FileGlob%"
') DO (
  IF /I "!_CurrentFile!" EQU "%%A-%%B" (
    ECHO.Deleting: "%_PathToCheck%\%%A-%%B-%%C"
    DEL /F /Q "%_PathToCheck%\%%A-%%B-%%C"
  ) ELSE (
    ECHO.
    ECHO.New File Found: "%%A-%%B"
    ECHO.-----------
    ECHO.Retaining: "%_PathToCheck%\%%A-%%B-%%C"
    SET "_CurrentFile=%%A-%%B"
  )
)

Example Output:

Y:\>Y:\t\DT.cmd

New File Found: "PLOG - File Three For yoU "
-----------
Retaining: "Y:\T\DT\PLOG - File Three For yoU - 2019.08.11 - (something) AAA 1 .xlsx"

New File Found: "PLOG - File Number Two "
-----------
Retaining: "Y:\T\DT\PLOG - File Number Two - 2019.12.19 - Ending ABDC 1111 AB.xlsx"
Deleting: "Y:\T\DT\PLOG - File Number Two - 2019.07.30 - Ending ABDC 1111 AB.xlsx"
Deleting: "Y:\T\DT\PLOG - File Number Two - 2019.03.12 - Ending Number 3 .xlsx"

New File Found: "PLOG - File Number One "
-----------
Retaining: "Y:\T\DT\PLOG - File Number One - 2020.01.01 - Ending BBB .xlsx"
Deleting: "Y:\T\DT\PLOG - File Number One - 2019.12.19 - Ending BBB 2 .xlsx"
Deleting: "Y:\T\DT\PLOG - File Number One - 2019.09.07 - Ending AAA1.xlsx"
Deleting: "Y:\T\DT\PLOG - File Number One - 2017.01.03 - Ending AAA 1 .xlsx"

Y:\>

Screenshot confirming the Script works and showing the Output and results:

Confirms the script works as described.

Essentially this does the same thing as in my original version only now we know that we should be looking for the Hyphens

IE:

We use DIR to Sort the File names in a reversed sort order, this will mean that files that have a newer date it will appear before those with older dates.

This simplifies the logic for deleting the files, and is the crux of my original solution as well.

Because of using that method we only need to check if the first part of the file name (the part before the date) is the same as the previous file found.

We do this by creating a variable to hold the name of the current file _CurrentFile and set it empty, so on the initial check, it will not match any file name.

If _CurrentFile matches the first part of the file name (again, the part before the date) o the file dir found, then we can safely delete it.

If _CurrentFile does not match the interesting portion of the file reported by the DIR cmd, then we update the _CurrentFile variable to that new value and move on to the next file result to test.

As you are unfamiliar with cmd/batch scripting, I would like to take a minute to go into more detail about what the script is doing and why for you so you can go forward yourself:

First I should note that we have a few options on how to iterate the files, most commonly for, for/F, and For files are common go-to for looping over files, sometimes with a DIR cmd in a for /F alternatively with a WMIC file list (although, thankfully WMIC is finally getting deprecated in favor of Powershell).

As we know you simply wat to Choose based off its Filename and the date stored in the file name, then using a dir cmd to sort by Name will be a pragmatic method to do the matching quickly

Now onto what each part of the script is doing

@(

Parenthesis create code blocks in CMD and Batch Script, everything within a given Parenthesis will be evaluated at the same time.

By placing an @ in front of the parenthesis any commands with it ( And not within further parenthesis, or after a DO ) will not be echoed to the screen. This is to stop this section form showing up and cluttering output.

  SetLocal EnableDelayedExpansion

We are turning on Delayed Expansion, to allow us to easily evaluate the contents of the variables inside of a for loop by referencing them with !_var! instead of %_Var%, technically we can get away without this if any of your filenames have ! in them, we should disable this and re-write it a bit, if not then it's fine.

  ECHO OFF

I am stopping the script from echoing every line it is doing so we have less cluttered output. Setting this command means I no longer have to use @ in front of further commands within this code block or future code outside this block.

  SET "_PathToCheck=Y:\T\DT"
  SET "_FileGlob=PLOG - * - ????.??.?? - *.xlsx"
  SET "_CurrentFile="
)

Setting the variables and closing the code block with a closing parenthesis seems self-explanatory except for one _FileGlob

This is a standard File Glob it is used to match the name of the file you want to have considered for comparison.

* matches any character any number of times, ? matches any character once. This ensures that if we encounter files which don't conform to the format we expect we can skip them.

If the need required a more explicit matching, we might use a glob of *.xlsx and use FINDStr to check against a regex pattern to make sure the format was very exactly the one needed.

in this next part

 FOR /F "Tokens=1-2* Delims=-" %%A IN ('
  DIR /A-D /O-N /B "%_PathToCheck%\%_FileGlob%"
') DO (
   [Code]
)

Now I am going to go a little out of order here:

We are using DIR to quickly sort the files by Their Name in reverse order and return just the filenames. DIR is extremely fast at doing this, so it's preferable if you are doing a little sorting rather than matching the files using IF compares later. We utilize the file glob as mentioned above to ensure only files we want to evaluate are returned.

The Option /A-D ignores directories, /B will only output the file name (since we aren't recursing) Then, we have /O-N -- /O is "Order By" the Option N sorts by Name ascending, while -N sorts by name in Reverse (Descending) Order (IE Z-A 9-0), so we can be assured that the file with the name that has the newest date will be the first one we find.

This is all placed inside a For /F Loop which is a way to parse the output of a command. We use Delims=- to "Tokenize" or Split-up the strings FOR is receiving from the DIR command. We Tell FOR what Variable names to store the Tokes in using %%A (Variables are as follows: "? @ A B C D E F G H I J K L M N O P Q R S T U V W X Y Z [ \ ]" OR "_ `` a b c d e f g h i j k l m n o p q r s t u v w x y z" { ( More info here https://ss64.com/nt/for_f.html ) ), Variables we be assigned to Tokens starting with the one you chose.

When we specify the tokens to pick, Tokens=1-2*", specifically 1-2 means to take the first Token through the second token, and store them in the First N variables (where N = the number of variables in the set 1-2, ie %%A and %%B for our purposes), and * means stop tokenizing anything after any tokens mentioned prior to this point, and place all of the remaining portions of the line into the next variable (%%C).

Because we are tokenizing use the Hyphen as a delimiter, we now that the first two tokens will be PLOG and [Name to Compare while the date and the rest of the file name will be in the 3rd token.

In the DO ( ) section we are going to go on and process the info returned by each line and stored in our tokens.

Lets go on to examine the code within the DO ( )

  IF /I "!_CurrentFile!" EQU "%%A-%%B" (
    ECHO.Deleting: "%_PathToCheck%\%%A-%%B-%%C"
    DEL /F /Q "%_PathToCheck%\%%A-%%B-%%C"
  ) ELSE (
    ECHO.
    ECHO.New File Found: "%%A-%%B"
    ECHO.-----------
    ECHO.Retaining: "%_PathToCheck%\%%A-%%B-%%C"
    SET "_CurrentFile=%%A-%%B"
  )

This is probably familiar to you enough as you are used to VBA, but we are testing the value of the variable _CurrentFile to the First Two Portions of the string, which we know are the entire portion of the file name up to the Date, and we need to add the Hyphen back in because when FOR splits by tokens it removes those tokens.

We check is the _CurrentFile variable ia a match for the currently returned file name's portion up to, but not including the date.

If this matches, we delete (Del) the file because we have already seen the file once before so this is one that is older.

We use the /F Option to Force deleting read-Only Files, and we use /Q to stop it from prompting us to confirm the deletion of each file.

We also ECHO. that we are deleting the file we found to note what the script is doing.

  ) ELSE (

If this does not match, that means this is a new file we haven't encountered for, and must be the first one returned, in which case we want to keep it because we know from the sort of Dir that it will be the interesting file.

Therefore on a non-match, we change the _CurrentFile variable to hold the value of the first two tokens %%A-%%B to use in future checks of the results returned.

We also ECHO. that we found the file and are retaining it to give a nice little indicator of what the script is doing.

A further note on ECHO -- Although I like how Echo. looks, ECHO( is safer to use, and I prefer it for that reason, but it is more confusing for folks who are unfamiliar with cmd scripts as the Open parenthesis looks like I have either a typo or an unclosed code block and can lead to people thinking it causes some problem. So for this reaosn, I try to avoid using ECHO( in favor of ECHO. when ECHO. will do.

Original Post and Versions Which used the incorrect format

You can make this a quite simple script that basically finds each unique name and keeps the 1st one so long as your names are in YYYY.MM.DD.xlsx format by pre-sorting the names so that the one with the newest date in the name one is always the first file encountered.

The Space is guaranteed? Optional?

to do this you need to use a FOR /F loop to parse the output from DIR ordered by (/O) Name Descending (-N)

DT.CMD:

@(
  SetLocal EnableDelayedExpansion
  ECHO OFF
  SET "_PathToCheck=Y:\T\DT"
  SET "_FileGlob=* ????.??.??.xlsx"
  SET "_CurrentFile="
)

FOR /F "Tokens=*" %%A IN ('DIR /A-D /O-N /B "%_PathToCheck%\%_FileGlob%"') DO (
  SET "_TFile=%%~nA"
  SET "_TFile=!_TFile:~0,-10!"
  IF /I "!_CurrentFile!" EQU "!_TFile!" (
    ECHO.Deleting: "%_PathToCheck%\%%~A"
    DEL /F /Q "%_PathToCheck%\%%~A"
  ) ELSE (
    ECHO.
    ECHO.New File Found: !_TFile!
    ECHO.-----------
    ECHO.Retaining: "%_PathToCheck%\%%~A"
    SET "_CurrentFile=!_TFile!"
  )
)

We then simply need to compare the names of the files except for the Trailing YYYY.MM.DD.xlsx, and if the File is the 1st with that name we keep it, as we know it will be the newest.

If the name is a duplicate we can delete it because we know we already skipped the newest.

Example Output:

Y:\>Y:\t\DT.cmd

New File Found: bananas 
-----------
Retaining: "Y:\T\DT\bananas 2019.07.01.xlsx"

New File Found: oranges 
-----------
Retaining: "Y:\T\DT\oranges 2019.09.01.xlsx"
Deleting: "Y:\T\DT\oranges 2019.07.11.xlsx"

New File Found: apples 
-----------
Retaining: "Y:\T\DT\apples 2019.07.07.xlsx"
Deleting: "Y:\T\DT\apples 2019.07.01.xlsx"

If your Date format is instead YYYY.DD.MM.Xlsx

Then you will need to go through an extra hoop or two.

Essentially in that scenario, we can do the following:

save the File name as a variable with the corrected (sortable) version of the file name (YYYY.MM.DD format) and then sort it and then compare the array of variables, deleting the ones which are not newest.

Here is that version DT_DM.CMD:

@(
  SetLocal EnableDelayedExpansion
  ECHO OFF
  SET "_PathToCheck=Y:\T\DT"
  SET "_FileGlob=* ????.??.??.xlsx"
  SET "_CurrentFile="
  SET "_MatchList= "
)

FOR /F "Tokens=*" %%A IN ('DIR /A-D /ON /B "%_PathToCheck%\%_FileGlob%"') DO (
  SET "_TFile=%%~nA"
  SET "_TFileMD=!_TFile:~-5!"
  SET "_TVar=__!_TFile:~0,-5!!_TFileMD:~-2!.!_TFileMD:~0,2!"
  REM ECHO.Storing File: "%%~A" As: "!_TVar!"
  SET "!_TVar!=%%~A"
  IF /I "!_CurrentFile!" NEQ "!_TFile:~0,-10!" (
    ECHO.New File Found, Adding to Sort List: "!_TFile:~0,-10!"
    SET "_CurrentFile=!_TFile:~0,-10!"
    SET "_MatchList=!_MatchList! "__!_TFile:~0,-10!""
  )
)

ECHO.
ECHO.Delete Old Files
ECHO.-----------------

REM Loop the Matched Files:
FOR %%a IN (%_MatchList%) DO (
ECHO.
ECHO.Delete Old %%a Files
ECHO.-----------------
  REM Loop the SET sorted for each File Found and Skip the First one (Newest), deleting the others.
  FOR /F "Skip=1 Tokens=1-2 Delims==" %%A IN ('SET "%%~a" ^| SORT /R') DO (
    ECHO.Deleting: "%_PathToCheck%\%%~B"
    DEL /F /Q "%_PathToCheck%\%%~B"
    REM Remove the deleted file variable so we can print a list of retained files at the end:
    SET "%%A="
  )
)

ECHO.
ECHO.Retained Files:
ECHO.-----------------
FOR %%a IN (%_MatchList%) DO ( SET "%%~a" )

Here is example output from that:

Y:\>Y:\t\DT_DM.cmd
New File Found, Adding to Sort List: "apples "
New File Found, Adding to Sort List: "bananas "
New File Found, Adding to Sort List: "oranges "

Delete Old Files
-----------------

Delete Old "__apples " Files
-----------------
Deleting: "Y:\T\DT\apples 2019.07.07.xlsx"
Deleting: "Y:\T\DT\apples 2019.12.01.xlsx"

Delete Old "__bananas " Files
-----------------

Delete Old "__oranges " Files
-----------------

Retained Files:
-----------------
__apples 2019.12.01=apples 2019.01.12.xlsx
__bananas 2019.01.07=bananas 2019.07.01.xlsx
__oranges 2019.11.07=oranges 2019.07.11.xlsx

Now, both of these examples Assume that you ALWAYS want whatever file is Named with the Newest Date, not the most recently modified file

This is probably the case as I know I usually want to have that scenario when working with my own dated files, in case someone or some process came along and modified the files, or I saved more than one out of order.

But just in case you really wanted to just retain the most recently modified file, we can Use the same concept as in the second version and save the Real Modified time to the Variables instead of the date on them.

DT_Modified.CMD:

@(
  SetLocal EnableDelayedExpansion
  ECHO OFF
  SET "_PathToCheck=Y:\T\DT"
  SET "_FileGlob=*.xlsx"
  SET "_CurrentFile="
  SET "_MatchList= "
)

FOR %%A IN ("%_PathToCheck%\%_FileGlob%") DO (
  ECHO.%%A| FINDStr /I " [0-9][0-9][0-9][0-9]\.[0-9][0-9]\.[0-9][0-9]\.xlsx$" >NUL && (
    SET "_TFile=%%~nA"
    SET "_TVar=__!_TFile:~0,-10!%%~tA"
    ECHO.Storing File: "%%~A" As: "!_TVar!"
    SET "!_TVar!=%%~A"
    IF /I "!_CurrentFile!" NEQ "!_TFile:~0,-10!" (
      ECHO.
      ECHO.New File Found, Adding to Sort List: "!_TFile:~0,-10!"
      ECHO.
      SET "_CurrentFile=!_TFile:~0,-10!"
      SET "_MatchList=!_MatchList! "__!_TFile:~0,-10!""
    )
  )
)

ECHO.
ECHO.Delete Old Files
ECHO.-----------------

REM Loop the Matched Files:
FOR %%a IN (%_MatchList%) DO (
ECHO.
ECHO.Delete Old %%a Files
ECHO.-----------------
  REM Loop the SET sorted for each File Found and Skip the First one (Newest), deleting the others.
  FOR /F "Skip=1 Tokens=1-2 Delims==" %%A IN ('SET "%%~a" ^| SORT /R') DO (
    ECHO.Deleting: "%_PathToCheck%\%%~B"
    DEL /F /Q "%_PathToCheck%\%%~B"
    REM Remove the deleted file variable so we can print a list of retained files at the end:
    SET "%%A="
  )
)

ECHO.
ECHO.Retained Files:
ECHO.-----------------
FOR %%a IN (%_MatchList%) DO ( SET "%%~a" )

Example of First Script Running ad results:

Example of First Script Running ad results:

Ben Personick
  • 3,074
  • 1
  • 22
  • 29
  • thanks so much for the detailed answer! I am trying to get the first example to work as that most closely describes what I need but it is not deleting the files. – Greg Williams Jul 11 '19 at 14:23
  • What is the output from the script when run in the CLI? I tested using the examples provided and generated the output from them. I'll run a quick test again using the dummy names you provided to see what happens in case I didn't put up the newest code. – Ben Personick Jul 11 '19 at 14:32
  • @GregWilliams I ran the script again using the file si most recently had in the directory, and they were deleted as expected. I updated the answer with a screenshot of this, and I also confirmed that it handles having more spaces just fine as well. Is it possible that the format of the files is not `[NAME][SPACE][YYYY.MM.DD].xlsx` ? Could the Names have Exclamation points ( `!` ) in them? – Ben Personick Jul 11 '19 at 14:46
  • here is an example of one of the filenames: "PLOG - Organic Valley - 2019.07.10 - (DAI) OG Cream Cheese.xlsx" I added the output the top/original post That is my fault for not specifying that the date is in the middle. Sorry! – Greg Williams Jul 11 '19 at 14:57
  • @GregWilliams Will the Date ALWAYS be prefixed and postfixed by `[Space][Hyphen][Space]` ? IE: `[Space][Hyphen][Space][YYYY.MM.DD][Space][Hyphen][Space]` – Ben Personick Jul 11 '19 at 15:17
  • unfortunately yes, thats how we do it here – Greg Williams Jul 11 '19 at 15:20
  • @GregWilliams Also, I assume that the first and second half of the names are unique? IE: will "PLOG - Organic Valley" could have "(DAI) OG Cream Cheese", or something different, IF something different then it ISNT the same file, is that correct? – Ben Personick Jul 11 '19 at 15:22
  • here is a picture of what the folder looks like as I think typing it would get confusing: https://photos.app.goo.gl/4qcwfhfzPnzvs2MH8 – Greg Williams Jul 11 '19 at 15:28
  • @GregWilliams Also, this is actually the almost the exact format I use for my own Files `[String1] - [YYYY-DD-MM_NN] - [String2].[ext]` , but I just need to be certain of what elements in the file name are considered "Unique" to be compared (IE if any part of the Unique Portions Differs, then the file is NOT the same as another file found. It may be only the first string changes are different files, and the string following the date is not consequential. – Ben Personick Jul 11 '19 at 15:31
  • @GregWilliams Okay, so then they always start with `PLOG - ` so Every file meets this format `PLOG - [String1] - [Date] - [String2].[ext]` Can I assume that `String2` can be ignored? IE that If the first part of the name is a match, then the second part being different will not matter? – Ben Personick Jul 11 '19 at 15:35
  • basically the script needs to compare two files. the only thing that will need to change will be the date in YYY.MM.DD format; all other aspects of the two filenames will be the same. This is more or less what I am currently doing manually. I upload the new version of the excel file and then go into the folder and find any duplicates (if they exist) and delete the one with the older date. – Greg Williams Jul 11 '19 at 15:36
  • okay, then easy peasy again, thanks – Ben Personick Jul 11 '19 at 15:37
  • @GregWilliams Okay, I amended the script to work with the file format you have, and posted it at the top, I explained the process in detail again, and provided example output and a screenshot of it, I put the old versions of the answers below this as thye may be helpful to others in the future. – Ben Personick Jul 11 '19 at 16:24
  • that worked! thank you, you are an all-star and huge time saver! I want to get better at C++ as I want to further script/automate my daily tasks here. What is a good source for me to learn how to manipulate code like what you presented above? – Greg Williams Jul 11 '19 at 16:36
  • also, could you explain how you code works. I'm pretty fluent in VBA so i can infer a lot of it but I dont understand some of the language in there. thanks again! – Greg Williams Jul 11 '19 at 16:43
  • @GregWilliams Yes, I put in details at several points about what we are doing and why from a logical standpoint but I also wanted to include a detailed breakdown fo you as well ad thought I had but I never copied it over, I will amend for the newest code ad include it. – Ben Personick Jul 11 '19 at 16:57
  • @GregWilliams Updated – Ben Personick Jul 11 '19 at 17:52
  • thank you so much for the explanation, im going to save this post so that hopefully i dont have to bug experts like yall too much in the future :) – Greg Williams Jul 11 '19 at 18:10
  • @GregWilliams Glad to help! Don;t forget to click the up vote on the answer too :) – Ben Personick Jul 11 '19 at 19:55
  • so we ran into a little issue when running your code on a larger data set and found that it was not comparing the back half of the file name in order to determine uniqueness. How do I alter the code to account for the filename both in front of and behind the date? Do I add a `%%C` or introduce a `'CurrentFile2` in order to compare the back half of filename? – Greg Williams Jul 23 '19 at 21:35
  • @GregWilliams Yeah, that's why I inquired as to whether you needed that part checked too, I had a suspicion it was needed, sorry that you didn't realize it was before or I woudl have written it that way. – Ben Personick Jul 23 '19 at 21:51
  • @GregWilliams To make that work appropriately we need to "re-arrange" the File Name, I started I just add in the extra variable but I'm sure that won't be enough as the Date sort will end up having duplicate files being saved otherwise, I have to go pick up the kids though or I woudl just finish writing that up. – Ben Personick Jul 23 '19 at 22:10
  • No worries, I really appreciate all of your help on this! How would I go about writing that? In VBA I would break things into columns first and then compare but how do you break it down like that in a batch file? – Greg Williams Jul 24 '19 at 12:16
  • @GregWilliams I go into detail of how the batch script commands work, and I wrote a logical overview of what each of the ones I wrote previously was doing. I woke up this morning with an easier track to make a minor change to the existing script and accomplish your goal. I don't have time to test but any issue woudl likely be syntax only. – Ben Personick Jul 24 '19 at 12:33
  • @GregWilliams I posted it on the top for you with a section explaining what was changed. Take a moment to vote up this solution, thanks! – Ben Personick Jul 24 '19 at 12:51
  • thank you for much for your help with this! I'm not sure if I am doing something wrong now because I am double clicking on the batch file and nothing happens (screen just flickers with the cmd terminal opening and closing quickly). – Greg Williams Jul 25 '19 at 12:09
  • @GregWilliams Probably a syntax error will take a look later today. – Ben Personick Jul 25 '19 at 12:47
  • @GregWilliams Had the time right now, this is tested and working, I used `IF EXIST` when I meant to use `IF DEFINED`. Whoops! if that works for you please vote up the solution, thanks! :) – Ben Personick Jul 25 '19 at 13:03
  • success; you're a rock star! thank you again! – Greg Williams Jul 25 '19 at 14:51