Sunday, March 10, 2013

Batch rename of folders in Windows

We used to back up all our digital photos to CDs and DVDs.  Now I have a Network-attached storage (NAS) device that I'm backing them up to (with a lot of other things) I wanted to get the photos from those CD/DVDs and get them on the NAS so I would have all the photos in one spot (well, I do back that up too, but maybe that's a topic for another day). So I spent some time copying them off the discs and putting them into a temporary folder on my computer planning to do one big copy to the NAS.

I figured out a while ago that I wanted to store my photos organized by time stamp.  So there is a folder for each year and inside that there are folders named in the format of  "YYYY-MM-DD".  The complication is that all the folders on those discs I mentioned were made before I decided on this convention.  Most of them were stored as "MM-DD-YYYY".  Now the main reason I like "YYYY-MM-DD" is because it sorts nicely, that's really about it.

So,  How do I name about 4 years worth of windows directories from "MM-DD-YYYY" to "YYYY-MM-DD" quickly?  Well, I wrote a batch file to do it.  Since I had all the folders I wanted to rename in one directory all I had to do was step through each one that matched the pattern I wanted to change, and issue the command to change them.

The problem is to rename something you need to know the old name, and the new name.  So I needed to be able to move the year. month and day part of the name around independently for each one.  Well, that's what I learned today.

The batch file I ended up with, which worked for the most part is here and nice and short:
@Echo on & SetLocal EnableExtensions
For /F "tokens=1,2,3* delims=-" %%I IN ('dir /ad /b ??-??-????')
       DO rename "%%~I-%%~J-%%~K" "%%~K-%%~I-%%~J"

To break it down, line one:
@Echo on & SetLocal EnableExtensions

Basically turns on "echo" so I can see what it is doing while it's working. The "SetLocal EnableExtensions" inherits the environment from the parent environment and keeps any environment changes I make local to this batch file and probably don't need it for this little run.

The second line is the complicated one:
For /F "tokens=1,2,3* delims=-" %%I IN ('dir /ad /b ??-??-????')

The first thing you see is the "For" loop, which lets me do the same thing over and over on a set of items. The set I want to step through is the Windows folders with the names I want to change.  The "/F" turns on file parsing (so we can muck with the names). The "IN ('dir /ad /b ??-??-????')" gives me that, basically saying give me all the directories (by running the "dir" or directory listing command with the "/ad" options which tell it to just list directories/folders) that have the name matching the pattern "??-??-????" (I'm not going to explain pattern matching :-).  The "%%I IN"of the "for" loop says when I'm in the loop, the item I'm supposed to be working on now is called (referenced by) the variable called "%%I".

Now the third line is what we do through each iteration of the loop:
DO rename "%%~I-%%~J-%%~K" "%%~K-%%~I-%%~J"

We simply run the Windows "rename" command and the syntax is pretty much current name first, then the new name you want it changed to.  Now we just need to explain all the gobbledygook in there.  That is where the "tokens" and "delims" file parsing features (that we turned on with the "/F") of the "for" loop come in.  They basically help you parse the items of the set as you step through them and this is how those two items break down:
  • "delims=" specifies a delimiter set, or what separates the pieces you want. Whatever characters you specify replaces the default delimiter set of space and tab.
  • "tokens=" specifies which tokens or pieces from each line are to be passed into the "for" loop body for processing.
You can look up all the syntax details, but to break it down the "tokens=1,2,3* delims=-" says the pieces I want are between each "-" (that's the "delims=-") and that I want the first three of them ("tokens=1,2,3*"). It automatically adds variables for me to use after the "%%I", putting the first piece I want into there, so that's why there is also a "%%J" (the second piece) and a "%%K" (the third piece).

Oh, you may have noticed the tilde ("~") in the names.  That's a variable modifier that basically means when you use what is in here, expand it, which removes any surrounding quotation marks ("").

So the "%%I" variable holds the MM, "%%J" holds the DD and "%%K" holds the YYYY.  So shuffling the order around using the rename command is basically saying here is my original directory name "%%~I-%%~J-%%~K" and here is the new name I want it to have "%%~K-%%~I-%%~J".

So, I put the three lines I started talking about way up at the top into a file called "renam.bat" and put it into the same directory where all the "MM-DD-YYYY" named directories were. Then I ran it by opening a "cmd" window and changing to the directory where all this stuff was sitting.  I ended up with all the directories renamed into the "YYYY-MM-DD" format.

The only glitch was that I had some directories named differently. Some didn't have all the digits of the dates, like "MM-DD-YY" or "M-D-YY", and they just didn't get processed.  Others were of the format "MM-DD-YY-Something" and those did get processed.  Luckily, that's what the asterisk in the "tokens" keyword is for, it tells it to keep anything after piece three as a part of piece three. So a couple of the names got slightly jumbled, but all those special cases were easy enough to fix by hand.  I didn't want to spend the time working on them in the script as there were only a few of them.

Of course there is probably several ways this could have been done, and probably some more elegantly.  But I learned something new (the "tokens" and "delims" stuff) and it worked, and it was quick because there were a lot of directories that needed to be renamed and now all my photos are copying to the NAS as I type this up.   So I'm happy.

To get it to work under Windows XP (Per the comment below) just make the "for" command be one line long.  Remove the carriage return before the "DO" and it works.  I just tested it on a XP VM.

For /F "tokens=1,2,3* delims=-" %%I IN ('dir /ad /b ??-??-????') DO rename "%%~I-%%~J-%%~K" "%%~K-%%~I-%%~J"

Thanks

10 comments:

  1. I have tried your batch file under windows xp (cmd window) but it is not working (it says 'syntax of the command is incorrect....) - do you have a version for xp?

    ReplyDelete
  2. This comment has been removed by a blog administrator.

    ReplyDelete
  3. Thanks mate, worked a treat. Mine were in DD-MM-YYYY so had to change the I and J around. To get the single date directories (eg D-MM-YYYY), I just changed the search pattern to match (?-??-????).

    ReplyDelete
  4. Thanks! The missing link in sorting my iPhone photo's in seperate-date-folders-batchfile. The batch file I had gave DD-MM-YYYY. With these extra commands I end up with YYYY_MM_DD. That's better for my OCD ;)

    ReplyDelete
  5. Thank you Tony for this helpful blog post! I was able to adjust your Batch-File to my needs.

    "rename_folders_from_dd.mm.yyyy_to_yyyy-mm-dd.bat"
    @Echo on & SetLocal EnableExtensions
    For /F "tokens=1,2,3* delims=." %%I IN ('dir /ad /b ??.??.????') DO rename "%%~I.%%~J.%%~K" "%%~K-%%~J-%%~I"

    ReplyDelete
  6. Hello! I need to convert DD.MM.YYYY to YYYY.MM.DD
    So I changed '-' to '.' in your example.
    Trying to run this batch on Windows 10 powershell as admin and separately - nothing happens. What am I doing wrong?
    @Echo on & SetLocal EnableExtensions
    For /F "tokens=1,2,3* delims=." %%I IN ('dir /ad /b ??.??.????') DO rename "%%~I.%%~J.%%~K" "%%~K.%%~I.%%~J"

    ReplyDelete
    Replies
    1. upd: Solved this exact task via "Bulk rename utility"

      Delete
  7. I didn't test this in powershell, I used windows batch (*.bat) files.

    ReplyDelete
  8. In my understanding Powershell is just more advanced ver. of Command prompt (cmd).
    Anyway... I couldn't figure it out... So I went for "Bulk rename utility" which is great though takes some time learning )

    ReplyDelete
  9. Hello, how do you tell .bat file which folders to rename from dd-mm-yyyy Friday to yyyy-mm-dd Friday ie my folder is Drive D: Folder Sony 2018-DL a rename folder would be great in Windows 10 hint hint … Microsoft.
    I Open Folder [view] file name Extensions and run as admin....

    ReplyDelete

What did you learn today?