HOWTO: Renaming Multiple Files

FROM: UNIX COMMAND LINE WORKSHOP
SKILL LEVEL: AGILE

Introduction

One of the great advantages of the UNIX cli is the ability to write commands that can perform multiple actions without manual imput. This is automation. It can be further extended by chaning together many commands and logging the output, as a task report for the human operator to check.

We’ll explore this here, working with a folder of images as an example, that need to be renamed.

Copying multiple files to a renamed backup

Assume I have a folder /home/julian/images/screenshots with hundreds of PNG files with unweildy names. I want to strip the redundant “Screenshot” from the file name in one motion:

julian@ce:~/images/screenshots$ ls -lh
total 401.6M
-rwxr----- 1 julian julian 103K Apr 18 14:39 Screenshot_2013-07-25-16-29-56.png
-rwxr----- 1 julian julian 333K Apr 18 14:39 Screenshot_2013-07-25-16-22-44.png
-rwxr----- 1 julian julian 142K Apr 18 14:39 Screenshot_2013-10-10-23-36-44.png
-rwxr----- 1 julian julian 226K Apr 18 14:39 Screenshot_2013-12-05-17-03-56.png
...

First I’m going to chain together a few commands to prepare using the shell ‘;’ separator.
I move up a level with cd, create a new folder to copy my renamed files into with mkdir and check my work with ls:

julian@ce:~/images/screenshots$ cd .. ; mkdir screenshots_renamed ; ls
screenshots  screenshots_renamed

Now I can write my command to rename the files, removing the “Screenshot” and copying the new files into my screenshots_renamed folder.

Command breakdown:

  • Move up a level with cd
  • Open a  ‘for loop’, creating a variable $old from each file output by ls
  • Create a variable $new from output of echoing $old to sed, replacing “Screenshot_” with nothing
  • Copy $old to our $new filename into our***screenshots_renamed*** folder.

Commands:

julian@ce:~/images$ cd screenshots
julian@ce:~/images$ for old in $(ls .); do new=$(echo $old | sed \ 's/Screenshot_//') ; cp $old ../screenshots_renamed/$new; done

Note the use of the ‘’ special shell character in the above commands. It allows us to line break without breaking the command itself.

Check if our command worked:

julian@ce:~/images$ ls -lh ../screenshots_renamed
total 401.6M
-rwxr----- 1 julian julian 796K Apr 18 15:15 2012-07-30-00-15-29.png
-rwxr----- 1 julian julian  98K Apr 18 15:15 2013-05-21-21-36-29.png
-rwxr----- 1 julian julian 243K Apr 18 15:15 2013-07-25-16-22-26.png
-rwxr----- 1 julian julian 333K Apr 18 15:15 2013-07-25-16-22-44.png
...

This can be all put into a script for use later. Here is an example script that use input variables and some testing (using if statements) to be sure we have what we need to perform the substution. Save it out as rename.sh and use chmod +x rename.sh to make it executable.

See the comments for a breakdown of how it works.

#!/bin/bash

# Simple script to renames files in the current directory. 
# Takes a directory and two strings as input arguments, denoting the replacement.
# Uses conditionals (if statements), shell variables, mkdir echo, sed and cp.

HELP="\n
************************************************\n
USAGE: ./rename.sh <directory> <original> <new>\n
Renames files in a given directory\n
Takes directory, text to find and text to \n
replace as input arguments\n
************************************************\n"
# First test we have all the input variables we need
if [ "$1" ] && [ "$2" ] && [ "$3" ]
    then
        # Test that our source directory exists
        if [ -d $1 ]
            then 
                DIR=$1
                # Make new variable, appending "_renamed" to $DIR input argument 
                NEWDIR=$DIR"_renamed" 
                # Make our new directory 
                mkdir $NEWDIR 
            else
                echo "The source directory doesn't seem to exist. Quitting..."
            exit
    fi
    # Perform substitution using input arguments $2 $3 and copy to $NEWDIR
    # Note use of double-quotes rather than single in our sed expression. 
    # This allows us to work with variables in the expression.
    for OLD in $(ls $DIR); 
        do NEW=$(echo $OLD | sed "s/$2/$3/");
        cp $DIR/$OLD $NEWDIR/$NEW; 
    done 
    echo "Performed substitution: "
    # List the results
    ls -lh $NEWDIR
else
    # If we don't have the expected input arguments, echo $HELP
    echo $HELP
fi