views:

63

answers:

2

I want to create a batch file that executes a command (delete the file, for a simple example, though my command is custom/different) on each file matching a wildcard (say *.jpg) that was modified since some date (such as 1-1-2010 or later). The date can either be hardcoded in the batch file or passed as a command line param.

Pseudocode:

foreach file C:\Images\*.jpg modified-since 1-1-2010 do
  del file

I'd prefer a pure batch file, not PowerShell, VBScript, etc. If using pure batch language isn't possible, I could use a small/free third-party command line program to assist with generating the modified-since file list. I need to support running in Windows 2000 or later.


The final solution I used:

(Slightly modified from the answer by pipitas)

@ECHO OFF
for /f "usebackq tokens=1-7* delims=/: " %%I in (`dir/o-d/tw ^| findstr /I .jpg`) do (
  if "%%K%%I%%J %%N %%L%%M" GEQ "20100801 AM 0000" (
    del /P %%P
  )
) 

Some notes: Remove /P to not require Y/N confirmation on each delete. I escaped the % characters so they would work inside a .bat file. The ^ is necessary to escape the pipe. The "usebackq" makes the backticks delimit a command to execute (instead of searching a literal string or file), tokens sets the number of variables to place the parsed line in starting with %I, and delims sets the delimiters (including the trailing space) used to parse the line into those tokens. I added .jpg as the findstr search string, since I only wanted to process .jpg files. Some possible problems are that your locale might print dates differently, requiring a different number of variables or different delimiters, and you might have some false positive matches with an embedded ".jpg" in the file name (requiring a findstr regex, etc.).

If you don't need to support Windows 2000 and earlier, using forfiles as suggested by Johannes would make this much easier.

+1  A: 

This should give you some ideas:

http://forums.techguy.org/dos-pda-other/772656-dos-batch-file-delete-folders.html http://www.computerhope.com/forum/index.php?topic=60404.0

del.ave
+1  A: 

First a few preliminaries:

  • dir /od /tw /s ..\path\to\somedir :
    lists all the directory's files+subdirs, sorted by date+time of last modification,
  • dir /o-d /tw /s ..\path\to\somedir :
    same, but in reverse order (oldest last).

Next, I use a local example for an existing path. Let's go:

dir /tc /o-d /s gstmp\*yell*.tif ^| findstr 2010
 Volume in Laufwerk C: hat keine Bezeichnung.
 Volumeseriennummer: D479-1658

 Verzeichnis von C:\downloads\gstmp

08/06/2010  05:01 PM           19 compression-g4-emptypage-tiffsep1(Yellow).tif
08/06/2010  05:00 PM           19 compression-lzw-emptypage-tiffsep1(Yellow).tif
08/06/2010  04:57 PM           19 compression-g3-tiffsep1(Yellow).tif
08/06/2010  04:57 PM           19 compression-crle-tiffsep1(Yellow).tif
08/06/2010  04:56 PM           19 compression-pack-share-tiffsep1(Yellow).tif
08/06/2010  04:53 PM           19 compression-g4-share-tiffsep1(Yellow).tif
08/06/2010  04:52 PM           19 compression-lzw-share-tiffsep1(Yellow).tif
08/06/2010  04:51 PM           19 compression-default-share-tiffsep1(Yellow).tif
08/06/2010  03:59 PM           19 compression-none-share-tiffsep.Yellow.tif
08/06/2010  03:55 PM           19 share-tiffsep.Yellow.tif
              10 Datei(en)       190 Bytes    

We don't like the additional header and summary info in this moment. We can get rid of this by filtering for something. I'll simply use '2010'.

But nNow the real problem starts: creation date and time can possibly be printed in different formats, depending on your 'locale'. You can see yourself, how it currently looks for me.

Wouldn't it be working, if we could make the date displayed in a format that would exactly match numerical order? Then we could implement some logic that decides about deletion through simple number comparison. Let's try (if this works for me, it will not necessarily work for you -- you may need to adopt to your locale). Note the 'backquotes' ("``") I'm using, as well as the ^-sign:

for /f "usebackq tokens=1-7* delims=/: " %I in (`dir/tc/o-d/s gstmp\*yell*.tif ^
   ^| findstr 2010`) do echo.    %I %J %K %L %M %N %O %P

Output here:

08 06 2010 05 01 PM 19 compression-g4-emptypage-tiffsep1(Yellow).tif
08 06 2010 05 00 PM 19 compression-lzw-emptypage-tiffsep1(Yellow).tif
08 06 2010 04 57 PM 19 compression-g3-tiffsep1(Yellow).tif
08 06 2010 04 57 PM 19 compression-crle-tiffsep1(Yellow).tif
08 06 2010 04 56 PM 19 compression-pack-share-tiffsep1(Yellow).tif
08 06 2010 04 53 PM 19 compression-g4-share-tiffsep1(Yellow).tif
08 06 2010 04 52 PM 19 compression-lzw-share-tiffsep1(Yellow).tif
08 06 2010 04 51 PM 19 compression-default-share-tiffsep1(Yellow).tif
08 06 2010 03 59 PM 19 compression-none-share-tiffsep.Yellow.tif
08 06 2010 03 55 PM 19 share-tiffsep.Yellow.tif

Almost there, but not fully yet. We need to change the order of our tokens %I %J %K to %K %I %J so that our date displays as 2010 08 06 instead of 08 06 2010. Also, if we write the right tokens without spaces, well get a date+time string so it can be easily compared. Plus, we skip the %O and replace it with an arrow, just for the fun of it:

for /f "usebackq tokens=1-7* delims=/: " %I in (`dir/tc/o-d/s gstmp\*yell*.tif ^
   ^| findstr 2010`) do echo.    %K%I%J%L%M%N ==^> %P

Output changes now to this:

201008060501PM ==> compression-g4-emptypage-tiffsep1(Yellow).tif
201008060500PM ==> compression-lzw-emptypage-tiffsep1(Yellow).tif
201008060457PM ==> compression-g3-tiffsep1(Yellow).tif
201008060457PM ==> compression-crle-tiffsep1(Yellow).tif
201008060456PM ==> compression-pack-share-tiffsep1(Yellow).tif
201008060453PM ==> compression-g4-share-tiffsep1(Yellow).tif
201008060452PM ==> compression-lzw-share-tiffsep1(Yellow).tif
201008060451PM ==> compression-default-share-tiffsep1(Yellow).tif
201008060359PM ==> compression-none-share-tiffsep.Yellow.tif
201008060355PM ==> share-tiffsep.Yellow.tif

Now you are nearly ready for comparing the first field.

But consider this: I get my times in cycles of 12 hours, with AM and PM. So in order to compare numerically, we have to replace PM and AM with a numerical value each, in such a way that our translation of 04:51 AM and 04:50 PM still will sort numerically in the right way.

Now how about this:

for /f "usebackq tokens=1-7* delims=/: " %I in (`dir/tc/o-d/s gstmp\*yell*.tif ^
     ^| findstr 2010`) do  (
        if "%K%I%J %N %L%M" GEQ "20100806 PM 0457"  (
            echo.   [ %K-%I-%J %L:%M %N    %P. ]
        )
 )

This lists all files which should be deleted, also showing their respective dates. To really delete, we just need to replace the last echo. ... %P. by a del/p/f/s %P.

pipitas
Thanks! Sometimes, I think batch files are Microsoft's revenge on us for something very bad we must have done. I made a few edits and got it to work. The pain of doing anything non-trivial in .bat files does make me reconsider not using VBScript, though.
Anagoge