Search code examples
windowsbatch-filecmd

How to mass rename files in a directory based on comparing file names in other directories sorted by size


I am attempting to make a batch script to rename a list of files based on matching names in another directory. My thought process for this goes something like this:

Things of Note

  • Files in directory 1 and 2 have the same names
  • Files in directory 2 and 3 have the same file size
  • Currently the script appears to do nothing and the files are unchanged
  1. Loop through all files in directory 3 and assign to an array by size
  2. Loop through all files in directory 2 and assign to an array by size
  3. Compare names in directory 1 to directory 2 and rename matching files to that of directory 3

Here is what I was able to come up with (I am quite unfamiliar with batch so forgive me):


@Echo off
setlocal enableextensions enabledelayedexpansion
set /a i = 0
set /a j = 0
set /a k = 0
set /a l = 0

for /f "delims=" %%f in ('dir "PATHtoDirectory3*extension" /o:s /b') do (
    set d3[%i%] = %%f
    set /a i += 1
)
for /f "delims=" %%g in ('dir "PATHtoDirectory2*extension" /o:s /b') do (
    set d2[%j%] = %%g
    set /a j += 1
)
for /f "delims=" %%h in ('dir "PATHtoDirectory1*extension" /o:s /b') do (
    set d1[%l%] = %%h
    for /l %%x in (1,1,100) do (
        if !d1[%l%]! == !d2[%k%]! (ren !d1[%l%]! !d3[%k%]!) else (set /a k += 1)
    )
    set /a l += 1
)
endlocal

Solution

  • An example would have been good.

    Suppose we have (file name size) in each of the 3 directories:

    dir1  dir2  dir3
    c  1  b  6  w  6
    d  2  c  7  x  7
    a  3  a  8  y  8
    b  4  d  9  z  9
    

    I gather the quest is to rename c to x, d,z a,y b,w in dir1.

    So - to your code (please use descriptive names - one-letter names are difficult to follow and may become confused with metavariables like %%x in your code)

    for /f "delims=" %%f in ('dir "PATHtoDirectory3*extension" /o:s /b /a-d') do (
        set /a i += 1
        set "d3[!i!]=%%f"
    )
    

    Add the /a-d switch to prevent dir from reporting directorynames ("good practice", even if you are sure (at the moment) there'll be no subdirectories)

    Increment the index, then store the data. This means you are dealing with d3[1..count] instead of d3[0..count-1]. This will make life easier.

    Remove the spaces around the = as those spaces will be assigned to both the variable-name and the value stored in a string-assignment. "Quote the statement" to ensure that any stray trailing spaces on the line are assigned to the value.

    You need the modified value of the index; !var! is the modified value, %var% is the value as it was when the statement was encountered (ie. parse-time)

    Repeat for all 3 loops.

    note that i, j and l should now each contain the number of filenames encountered. Presumably, these should be identical.

    Next problem is that if the filename in d3 is identical to any filename in d1, then you could be attempting to rename d1\xyz to abc when d1\abc already exists.

    Move the %%x loop from where it is to after the d1 array has been built.

    Note that you have the count of names in i, j and l, so you can use

    for /L %%x in (1,1,%i%) do ...
    

    to iterate across the array, you don't need to use an arbitrary number. You can nest for statements :

    for /L %%x in (1,1,%i%) do for /L %%y in (1,1,%i%) do ...
    

    and now you can simply compare the d1,d2 names using

    if "d1[%%x]"=="d2[%%y]"
    

    and if this is true then d3[%%y] contains the new name.

    To implement this, try

    pushd PATHtoDirectory1
    md tempdirname
    for /L %%x in (1,1,%i%) do for /L %%y in (1,1,%i%) do if "d1[%%x]"=="d2[%%y]" (
     move d1[%%x] .\tempname\d3[%%y]
    )
    move .\tempdirname\* .
    rd tempdirname
    popd
    

    Where the pushd switches the current directory to PATHtoDirectory1; create a temporary directory there;match each name and move the file to the new name in the subdirectory;move the files with their new names back to the main directory;remove the subdirectory and popd returns to the original directory from which the batch is run.

    Since the names in dir3 are unique, so the subdirectory will have unique names, and the rename to same or existing name problem is eliminated.