Skip to content

Instantly share code, notes, and snippets.

@mrzapp
Last active May 21, 2018 11:55
Show Gist options
  • Save mrzapp/aadd466e28cff60c4ef5b0fea64422e1 to your computer and use it in GitHub Desktop.
Save mrzapp/aadd466e28cff60c4ef5b0fea64422e1 to your computer and use it in GitHub Desktop.
A bash script for renaming photos downloaded using Google Takeout. It assigns a sensible file name to each photo and copies it to a new location with error logs and replicated directory structure.
#!/bin/bash
INPUT_FOLDER=$1
OUTPUT_FOLDER=$2
if [ -z "$INPUT_FOLDER" ] || [ -z "$OUTPUT_FOLDER" ]; then
echo "Usage: sort.sh <input folder> <output folder>"
exit 1;
fi
echo > "$OUTPUT_FOLDER/omitted.log"
echo > "$OUTPUT_FOLDER/failed.log"
CORRECT_FILE_REGEX='[1-2][0-9][0-9][0-9]-[0-1][0-9]-[0-3][0-9]_[0-2][0-9]-[0-5][0-9]-[0-5][0-9]'
UNIT_TIMESTAMP_MILLISECONDS_REGEX='([0-9]{13})'
UNIT_TIMESTAMP_SECONDS_REGEX='([0-9]{10})'
FOLDER_REGEX='([1-2][0-9][0-9][0-9])-([0-1][0-9])-([0-3][0-9])'
EXIF_REGEX='([1-2][0-9][0-9][0-9]):([0-1][0-9]):([0-3][0-9]) ([0-2][0-9]):([0-5][0-9]):([0-5][0-9])'
FILE_REGEX='([1-2][0-9][0-9][0-9])([0-1][0-9])([0-3][0-9])'
FILE_ALT_REGEX='([0-1][0-9])([0-1][0-9])([0-3][0-9])-([0-2][0-9])([0-5][0-9])([0-5][0-9])'
ANY_NUMBER_REGEX='([0-9]+)\.'
find "$INPUT_FOLDER" -print0 | while read -d $'\0' FILE; do
FILENAME=$(echo "$(basename "$FILE")" | cut -f 1 -d '.')
EXTENSION=$(echo "${FILE#*.}" | tr '[:upper:]' '[:lower:]')
if [ "$EXTENSION" != "jpg" ] && [ "$EXTENSION" != "jpeg" ] && [ "$EXTENSION" != "mts" ] && [ "$EXTENSION" != "mp4" ]; then
echo "$FILE" >> "$OUTPUT_FOLDER/omitted.log"
continue;
fi
if [[ $FILE =~ $CORRECT_FILE_REGEX ]]; then
echo "$FILE is OK"
continue;
fi
# Fetch the date from create date
EXIF_OUTPUT=$(exiftool -s -CreateDate "$FILE")
[[ $EXIF_OUTPUT =~ $EXIF_REGEX ]]
YEAR=${BASH_REMATCH[1]}
MONTH=${BASH_REMATCH[2]}
DAY=${BASH_REMATCH[3]}
HOUR=${BASH_REMATCH[4]}
MINUTE=${BASH_REMATCH[5]}
SECOND=${BASH_REMATCH[6]}
# Fetch the date from date/time original
if [ -z $YEAR ] || [ -z $MONTH ] || [ -z $DAY ]; then
EXIF_OUTPUT=$(exiftool -s -DateTimeOriginal "$FILE")
[[ $EXIF_OUTPUT =~ $EXIF_REGEX ]]
YEAR=${BASH_REMATCH[1]}
MONTH=${BASH_REMATCH[2]}
DAY=${BASH_REMATCH[3]}
HOUR=${BASH_REMATCH[4]}
MINUTE=${BASH_REMATCH[5]}
SECOND=${BASH_REMATCH[6]}
fi
# Fetch the date from media create date
if [ -z $YEAR ] || [ -z $MONTH ] || [ -z $DAY ]; then
EXIF_OUTPUT=$(exiftool -s -MediaCreateDate "$FILE")
[[ $EXIF_OUTPUT =~ $EXIF_REGEX ]]
YEAR=${BASH_REMATCH[1]}
MONTH=${BASH_REMATCH[2]}
DAY=${BASH_REMATCH[3]}
HOUR=${BASH_REMATCH[4]}
MINUTE=${BASH_REMATCH[5]}
SECOND=${BASH_REMATCH[6]}
fi
# Fetch the date from the filename
if [ -z $YEAR ] || [ -z $MONTH ] || [ -z $DAY ]; then
# YYYYMMDD format
if [[ $FILE =~ $FILE_REGEX ]]; then
YEAR=${BASH_REMATCH[1]}
MONTH=${BASH_REMATCH[2]}
DAY=${BASH_REMATCH[3]}
# YYMMDD-HHMMSS format
elif [[ $FILE =~ $FILE_ALT_REGEX ]]; then
YEAR="20${BASH_REMATCH[1]}"
MONTH=${BASH_REMATCH[2]}
DAY=${BASH_REMATCH[3]}
HOUR=${BASH_REMATCH[4]}
MINUTE=${BASH_REMATCH[5]}
SECOND=${BASH_REMATCH[6]}
# UNIX timestamp with milliseconds
elif [[ $FILENAME =~ $UNIX_TIMESTAMP_MILLISECONDS_REGEX ]]; then
TIMESTAMP=$(date -d @$(echo "($FILENAME + 500) / 1000" | bc) +'%Y:%m:%d %H:%M:%S')
[[ $TIMESTAMP =~ $EXIF_REGEX ]]
YEAR=${BASH_REMATCH[1]}
MONTH=${BASH_REMATCH[2]}
DAY=${BASH_REMATCH[3]}
HOUR=${BASH_REMATCH[4]}
MINUTE=${BASH_REMATCH[5]}
SECOND=${BASH_REMATCH[6]}
# UNIX timestamp with seconds
elif [[ $FILENAME =~ $UNIX_TIMESTAMP_SECONDS_REGEX ]]; then
TIMESTAMP=$(date -d @$FILENAME +'%Y:%m:%d %H:%M:%S')
[[ $TIMESTAMP =~ $EXIF_REGEX ]]
YEAR=${BASH_REMATCH[1]}
MONTH=${BASH_REMATCH[2]}
DAY=${BASH_REMATCH[3]}
HOUR=${BASH_REMATCH[4]}
MINUTE=${BASH_REMATCH[5]}
SECOND=${BASH_REMATCH[6]}
# Fetch the date from the folder
elif [[ $FILE =~ $FOLDER_REGEX ]]; then
YEAR=${BASH_REMATCH[1]}
MONTH=${BASH_REMATCH[2]}
DAY=${BASH_REMATCH[3]}
fi
fi
# Determine the output folder
THIS_OUTPUT_FOLDER=""
if [[ $FILE =~ $FOLDER_REGEX ]]; then
THIS_OUTPUT_FOLDER=$OUTPUT_FOLDER
else
THIS_OUTPUT_FOLDER="$OUTPUT_FOLDER/$(basename "$(dirname "$FILE")")"
fi
# Make sure the folder exists
if [ ! -d "$THIS_OUTPUT_FOLDER" ]; then
mkdir "$THIS_OUTPUT_FOLDER"
fi
# Build the filename
FILENAME=""
if [ ! -z $YEAR ] && [ ! -z $MONTH ] && [ ! -z $DAY ]; then
FILENAME="${YEAR}-${MONTH}-${DAY}"
else
echo "No date found for $FILE"
echo "$FILE" >> "$OUTPUT_FOLDER/failed.log"
continue;
fi
if [ ! -z $HOUR ] || [ ! -z $MINUTE ] || [ ! -z $SECOND ]; then
FILENAME="${FILENAME}_${HOUR}-${MINUTE}-${SECOND}"
else
# If no time was found, create an appendix
APPENDIX=0
[[ $(basename "$FILE") =~ $ANY_NUMBER_REGEX ]]
# If an existing appendix was found, use it
if [ ! -z ${BASH_REMATCH[1]} ]; then
APPENDIX=${BASH_REMATCH[1]}
# If not, construct one, and don't overwrite existing files
else
while ls "${THIS_OUTPUT_FOLDER}/${FILENAME}_${APPENDIX}."* 1> /dev/null 2>&1; do
let APPENDIX++
done
fi
FILENAME="${FILENAME}_${APPENDIX}"
fi
FILENAME="${FILENAME}.${EXTENSION}"
cp "$FILE" "$THIS_OUTPUT_FOLDER/$FILENAME"
echo "$THIS_OUTPUT_FOLDER/$FILENAME"
done
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment