Search code examples
macosunixterminalapplescriptbatch-rename

Mac: Batch rename (and renumber) files every n number of files


(macOS / Terminal question)

I am rendering frames of an animation sequence and need to slow down the whole thing to get sub-frame blur and composite each each final frame from four composited frames. This means extending the number of frames by 400%. However the software outputting the images can only output filenames sequentially and can't be instructed to group them.

The output for what will ultimately become 2 frames will look like this (8 frames):

Frame 1: 0001.png 0002.png 0003.png 0004.png

Frame 2: 0005.png 0006.png 0007.png 0008.png

To "stack" these in compositing, I need to remap them into "layers", let's call them A, B, C, D:

Frame 1: a0001.png b0001.png c0001.png d0001.png

Frame 2: a0002.png b0002.png c0002.png d0002.png

Then they could optionally be moved into folders quite easily, and composited from there:

The compositor will "step" according to the number in the file names. So as long as ABCD are aligned with the correct corresponding frame numbers, the problem is solved.

I have also installed a batch file renaming app called Transnomino, so if it's easier to do this using that app, I am open to doing it that way too. Or by using AppleScript in Automator, come to think of it. Thanks.


Solution

  • This should do both parts of what you need. The script makes some basic assumptions, e.g. that input files are names as in the question, e.g. "0001.png", but this is straightforward enough to change as required.

    First, it creates output sorting folders on the desktop, inside a 'frames' folder. It looks in a folder named 'inputs' on the desktop for your source files. It asks for a count of how many to process but it could be set to just grab every file in the folder.

    Next, it creates some lists: of frames (e.g. 0001, 0002), of frame file names (0001.png, 0002.png) and of prefixes (a, b, c, d).

    It then cycles through each frame and determines which letter should be prepended to its file name, builds the new file name and renames the file (using System Events). Finally, it cycles through the prefixes and moves all matching files to the appropriate sorting folder (based on the first letter).

    -- create frames destination folders
    do shell script "cd ~/Desktop ; /bin/mkdir -p frames/{a,b,c,d}"
    -- specify input and destination folders
    set inputDir to (path to desktop) & "inputs:" as text
    set frameDir to (path to desktop) & "frames:" as text
    
    set padX to {"000", "00", "0"} -- pads out to 3 zeroes, e.g. 0001
    set frameList to {}
    set nameList to {}
    set inputFrameCt to 4
    set inpFr to display dialog "Enter number of input frames" default answer 4
    set inputFrameCt to text returned of inpFr as integer
    
    repeat with x from 1 to inputFrameCt
        set y to x as string -- 1 to frame count
        set zx to item (length of y) of padX & y --  4 characters, e.g. 0005
        set end of frameList to zx
        set end of nameList to zx & ".png"
    end repeat
    frameList -- list of frame numbers, does not include extension
    nameList -- list of frame file names, includes extension
    
    set preList to {"d", "a", "b", "c"} -- letter to prepend to file name
    set fNameList to {} -- list of resulting file names
    
    tell application "System Events"
        repeat with f in frameList -- cycle through frame numbers
            
            set inFile to inputDir & item f of nameList -- frame's path and name
            set pre to item (f mod 4 + 1) of preList -- get appropriate prefix
            set preName to pre & item f of nameList -- frame's resulting file name
            set end of fNameList to (pre & item f of nameList)
            
            set name of file inFile to preName -- rename file, e.g. 0001.png > a0001.png
        end repeat
        
        set letterList to {"a", "b", "c", "d"}
        repeat with l in letterList
            set lFiles to (disk items of folder inputDir whose name begins with l)
            move lFiles to folder l of folder frameDir -- move files based on prefix
        end repeat
    end tell
    
    

    NB The script uses x mod 4 to determine which of the letters to use as the prefix. Since every fourth number will result in 0, it adds 1 and moves 'd' to the beginning of the list.

    Should you want to change the script in the future to account for a different ratio of frames, you could simply alter the various letter lists and change the mod value to match. It's easy enough to automate this so that you could just enter a single number and everything else would follow.