A Unix shell script to rename many files at one time

Summary: In this post I share a Unix/Linux shell script that can be used to rename multiple files (many files) with one shell script command.

Problem

You're on a macOS, Unix, or Linux system, and you'd like to be able to rename a large number of files at once. In particular, you'd like to be able to change the extensions of a large number of files, such as from *.JPG to *.jpg (changing the case of each file extension from upper case to lower case), or something similar.

Solution

Many years ago I created a Unix shell script to solve just this problem. I kept running into a combination of problems, including file extensions ending in uppercase characters, to files named *.htm that I wanted to renamed to *.html. Sure, you can change all these filenames manually, but hey, this is Unix, there must be a better way, right?

Usage

Hopefully you'll like this Unix shell script that I've named mmv, for multiple move. It's usage is very simple, you just specify the current file extension, and the new desired file extension, and it will move every file that matches the current file extension to the new extension.

Here's the command I would invoke to rename every file in the current directory that currently ends with the extension JPG, or .JPG to be more specific:

mmv PNG png

For a small directory with just three matching files, the output from the mmv script will look something like this:

Moving iphone1.JPG --> iphone1.jpg
Moving iphone2.JPG --> iphone2.jpg
Moving iphone3.JPG --> iphone3.jpg

As you can see, this script can be a great time saver. That being said, please read all the warnings and cautions carefully. Any "move" operation is dangerous, let alone an automated move operation.

Filenames with spaces

After the first comment on this article (shown below), I just re-wrote this script to deal with filenames that have spaces in them. I personally never create filenames with spaces in them, but when I wrote a script to convert CAF files to AIF files (AIFF, AIFC, WAV, MP3, etc.), I had to figure out how to deal with filenames that have spaces.

To test this new script, I created three filenames with spaces in them, like this:

touch "Foo Bar.txt"
touch "Bar Baz.txt"
touch "Bam Boom.txt"

Next, I tested my new script, like this:

mmv txt text

and in doing so, I saw the following output, and the filenames with spaces were renamed properly:

Moving "Bam Boom.txt" --> "Bam Boom.text" ...
Moving "Bar Baz.txt" --> "Bar Baz.text" ...
Moving "Foo Bar.txt" --> "Foo Bar.text" ...

I also re-tested my PNG and HTML examples above, and they worked fine as well.

That being said, automating a Unix/Linux mv command like this is still a dangerous thing to do, so please make a backup copy of your data to another folder before using this script.

The "multiple move" source code

Here's the source code for my mmv shell script. To run it, just save this text to a file named mmv on your Unix/Linux system, make sure that file is in your PATH, and make it executable (chmod +x mmv), and then give it a spin. Note that the "mv" command is commented-out by default. You'll have to manually remove that comment to get the actual move command to work, and I suggest only doing that after you run this script at least once with just the "echo" output.

#!/bin/sh
#
# Name:       mmv (a unix/linux "multiple move" script)
# Version:    2
# Purpose:    move all the files with the first filename extension 
#             to the second extension.
# Created By: Alvin Alexander, https://alvinalexander.com
# License:    GNU GPL v3.0 (https://www.gnu.org/licenses/gpl-3.0.en.html)
#
# Usage example 1:
#
#    mmv htm html  
#    (this renames all *.htm files to *.html)
#
# Usage example 2:
#
#    mmv PNG png  
#    (this renames all *.PNG files to *.png (effectively changing the case 
#    of all files)
#
# WARNINGS:
#
#    (1) Make a backup copy of your files and put them in a different directory
#        before using this script.
#    (2) This script may not work properly on filenames that have a space
#        in them. It worked fine on my small test on a Mac OS X system, but
#        this does not guarantee it will work properly on all systems.
#    (3) This script assumes your filenames have only one decimal (period)
#        character in the filename.
#    (4) This script only works in the current directory (which you can tell
#        from the "for" loop below).
#    (5) I have commented-out the "mv" command below and replaced it with
#        an "echo" command. Because you can lose data any time you perform a
#        move or copy operation, I strongly encourage you to run this script
#        with the echo command first, and if the output from the script looks
#        okay, then un-comment the mv command.


IFS=$'\n'

if [ -z "$1" ] || [ -z "$2" ]
then
  echo "Usage: mmv oldExtension newExtension"
  exit -1
fi

# list all files in the current directory that have the 
# first filename extension
for infile in $(ls -1 *.${1})
do

  # get the base filename by stripping off the first extension
  baseFilename=`basename "${infile}" .${1}`

  # determine the output filename by adding the second extension
  # to the base filename
  outfile="${baseFilename}.${2}"

  # tell the user what is happening
  echo "Moving \"$infile\" --> \"$outfile\" ..."

  # remove the comment below if and only if you have run this script once with just
  # the 'echo' output, and you've confirmed everything looks okay.
  # also, make sure you have a backup of your
  # files in another directory or on another system before
  # running this 'mv' command.
  # mv "$infile" "$outfile"

done

Warnings

I've added more warnings to the documentation of this script, because any time you perform a "move" or "copy" operation you have a chance of losing data. As mentioned in those warnings, the "mv" command in this script is now commented-out by default; you must remove the comment character before the mv command for the move to work; and you should only do that after running the script once and verifying the "echo" output is what you expect.