Bash – Rename Pictures to Image Taken

| | | |

Similar to “PowerShell – Rename Pictures to Image Taken“, this script will work on macOS and most Unix systems (Fedora/CentOS/Rocky/Red Hat (RHEL) and Ubuntu/Debian for example).

NOTE: This is an update to a previous posted version of this script. Both exist to provide some options. Previous post: BASH – Picture / Video File Name Manipulation

This script will:

  1. Ask if you want to assign a photographer to the picture, if not type nothing and press Enter/Return.
    1. If the provided name for the photographer is not alphanumeric each character will be replaced with an underscore so that the file name will work.
  2. Change capitalization of file extensions from JPG to jpg for example.
  3. Move any video files out of the directory to a separate directory
Bash
#!/bin/sh

# brew install imagemagick
# brew install exiftool

echo "Please type in the photographer name or simply press enter/return. "
read photographer

#region Pictures
#region Change Capitalization of Extensions
if [[ ! -z $(find . -type f -name "*.JPG") ]]; then
    echo "Changing case of JPG to jpg"
    for f in *.JPG; do
        mv -vf "$f" "${f%.JPG}.jpg"
    done
fi

if [[ ! -z $(find . -type f -name "*.jpeg") ]]; then
    echo "Changing jpeg to jpg"
    for f in *.jpeg; do
        mv -vf "$f" "${f%.jpeg}.jpg"
    done
fi

if [[ ! -z $(find . -type f -name "*.HEIC") ]]; then
    echo "Changing case of HEIC to heic"
    for f in *.HEIC; do
        mv -vf "$f" "${f%.HEIC}.heic"
    done
fi

if [[ ! -z $(find . -type f -name "*.NEF") ]]; then
    echo "Changing case of NEF to nef"
    for f in *.NEF; do
        mv -vf "$f" "${f%.NEF}.nef"
    done
fi
#endregion Change Capitalization of Extensions

# If a photographer is provided we will add an underscore and the name to the picture file.
# If the provided name has any spaces or characters that can not be a file name they are replaced.
if [ ! -z "$photographer" ]; then
    # If photographer was provided, remove any characters from the string that are not alphanumeric
    photo_photographer="_$(echo "$photographer" | sed 's/[^a-zA-Z0-9]/_/g')"
else
    # If photographer was not provided
    photo_photographer=""
fi

if compgen -G "*.jpg" >/dev/null || compgen -G "*.dng" >/dev/null || compgen -G "*.nef" >/dev/null; then
    # File is a picture that should have exif data

    # This first part will rename a picture based on the date and time the picture was taken.
    # NOTE: This will only work properly if you have the original files. It usually will not work if you downloaded the pictures from social media or other sources.

    mkdir -p DatedFiles/pictures
    mkdir -p NoDateFiles/pictures

    exiftool -r -d "%Y/%m/%Y-%m-%d_%H.%M.%s" '-FileName=NoDateFiles/%f%+c.%e' '-FileName<DatedFiles/${datetimeoriginal}_${imagesize}%-c.%e' -d "%Y-%m-%d_%H.%M.%S" .

    # This part will add the image size to the file name

    find DatedFiles/. -name \*.jpg -o -name \*.dng >picture_files.txt
    while IFS="" read -r picture || [ -n "$picture" ]; do

        filename=$(basename -- "$picture")
        extension="${filename##*.}"
        filename="${filename%.*}"

        # If photographer is defined then add it to the file name
        # cp -v ${picture} "rename/pictures/${filename}_${photographer}.${extension}"
        mv -v ${picture} "DatedFiles/pictures/${filename}${photo_photographer}.${extension}" # Once you are comfortable with the copy results you can comment/remove the copy and uncomment the move

    done <picture_files.txt
    rm -fv picture_files.txt

    find NoDateFiles/. -name \*.jpg -o -name \*.dng >picture_files.txt
    while IFS="" read -r picture || [ -n "$picture" ]; do

        filename=$(basename -- "$picture")
        extension="${filename##*.}"
        filename="${filename%.*}"

        # cp -v ${picture} "rename/pictures/${filename}_${photographer}.${extension}"
        mv -v ${picture} "NoDateFiles/pictures/${filename}${photo_photographer}.${extension}" # Once you are comfortable with the copy results you can comment/remove the copy and uncomment the move

    done <picture_files.txt
    rm -fv picture_files.txt

fi
#endregion Pictures

# region AVI, MP4, MOV
if compgen -G "*.avi" >/dev/null || compgen -G "*.mp4" >/dev/null || compgen -G "*.mov" >/dev/null; then

    find . -name \*.avi -o -name \*.mp4 -o -name \*.mov >video_files.txt
    while IFS="" read -r video || [ -n "$video" ]; do

        # Try to create a rename directory
        mkdir -p rename/videos

        filename=$(basename -- "${video}")
        extension="${filename##*.}"
        filename="${filename%.*}"

        newname="${filename}${photo_photographer}"

        echo "Original Name: ${video}"
        echo "New Name: $newname.${extension}"

        # cp -v "${video}" "rename/videos/${newname}.${extension}"
        mv -v "${video}" "rename/videos/${newname}.${extension}" # Once you are comfortable with the copy results you can comment/remove the copy and uncomment the move

    done <video_files.txt
    rm -fv video_files.txt
fi
# endregion AVI, MP4, MOV

#region Cleanup Empty Files/Directories
find . -depth \( -name "Thumbs.db" -o -name "desktop.ini" -o -name ".DS_Store" -o -name "._*" -o -name "SyncToy*.dat" -o -name "Picasa.ini" \) -type f -exec rm -rfv {} \;

# Remove empty files in general before delete empty directories
find . -depth -empty -type f -exec rm -rfv {} \;

# Delete empty directories
#find . -depth -empty -type d -delete
find . -depth -empty -type d -exec rm -rfv {} \;
#endregion Cleanup Empty Files/Directories
Originally Posted on June 21, 2025
Last Updated on October 15, 2025
All information on this site is shared with the intention to help. Before any source code or program is ran on a production (non-development) system it is suggested you test it and fully understand what it is doing not just what it appears it is doing. I accept no responsibility for any damage you may do with this code.