Shell script to rename odd numbered files

Recently, I accepted a Fiverr project to needed to sharpen and enhance a video. My Topaz Labs Video AI was unable to do anything useful, so I tried converting the entire video to photos and running through through their photo tools like Photo AI. Using the open source ffmpeg, I did it like this:

Movie to Images using ffmpeg

ffmpeg -i “input.mp4 frames-full/frame%d.jpg

That command creates jpg image files in a subfolder called “frames-full” for every frame of the original video. In my case, the original video was shot at 59.94 frames per second and created a ton of image files.

Processing 20,000+ images was going to take days, so I decided to just process it as 29.97 frames per second (standard US video rate) which would cut my processing time in half. To do this, I needed to delete every other image. I was able to use the “find” command to search for any matching filename that ended in 0, 2, 4, 6 or 8 (an even number):

find . -name "frame[0-9]*[02468].jpg"

One neat thing about the modern macOS file system is you can make a duplicate of a folder before doing something dangerous like command line deletes! The duplicate doesn’t take up extra space (beyond a bit of directory overhead) so that let me experiment over and over until I figured it out.

Now I had frame1.jpg, frame3.jpg, frame5.jpg and so on. After processing these files, I would need to re-assemble them using ffmpeg at the 29.97 frame rate. Here is the command for that:

ffmpeg -framerate 29.97 -I frames-full/frame%d.jpg -pix_fmt yuv420p output.m4v

Unfortunately, it expects all the files to be sequentially numbered (1, 2, 3, 4) and would not work with every other file missing.

To fix that, I needed a script that would rename files down from…

frame1.jpg
frame3.jpg
frame5.jpg
frame6.jpg
frame9.jpg

…to…

frame1.jpg
frame2.jpg (was 3)
frame3.jpg (was 5)
frame4.jpg (was 7)
frame5.jpg (was 9)

A bit of trail and error led me to this simple script that divides the number by 2, and since there is no floating point, all I needed to do was add one to the number and then do the division. 3 became 1+3 which is 4, which divided by 2 became 2:

1 -> 1+1 = 2 / 2 = 1
3 -> 3+1 = 4 / 2 = 2
5 -> 5+1 = 6 / 2 = 3
7 -> 7+1 = 8 / 2 = 4
9 -> 9+1 = 10 / 2 = 5

That let me simply rename the original number to the new number and get what I wanted. Here is the script, though it is hard coded to the number of files I needed. You’d have to change that since it’s not smart enough to figure this out (like, “stop when you find a file that doesn’t exist”). Also, it starts at 3 since frame1.jpg would be renamed to frame1.jpg which probably produces an error:

#!/bin/bash

# find . -name "frame[0-9]*[02468].jpg"

# Delete even-numbered files
for ((i=3;i<=26999;i=i+2))
do
    file="frame${i}.jpg"
    j=$((i/2+1))
    if [ -f "$file" ]; then
        echo "Renaming $file"
        mv "$file" "frame${j}.jpg"
    fi
done

I just wanted to post this here in case anyone else ever needs to do the same thing…

Until next time…

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.