Skip to content

Instantly share code, notes, and snippets.

@elisboa
Last active August 22, 2022 16:59
Show Gist options
  • Star 5 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save elisboa/631bbe8971a035c36b765f3fe19dacb4 to your computer and use it in GitHub Desktop.
Save elisboa/631bbe8971a035c36b765f3fe19dacb4 to your computer and use it in GitHub Desktop.
A simple script to sort photo files based on their exif information
#!/usr/bin/env bash
# ---
#!/bin/bash -x
echo -e "### WELCOME TO $0\n"
if [[ -z ${DEST_DIR} ]]
then
TIMESTAMP=$(date +%s)
echo -e "Setting destination dir as ${TIMESTAMP}"
DEST_DIR=${TIMESTAMP}
else
echo -e "Destination dir set as ${DEST_DIR}"
fi
if [[ -n "${1}" ]]
then
echo -e "Analyzing ${1}"
else
echo -e "Argument not set. Usage: ${0} file_name.jpg"
echo -e "\a"
exit 1
fi
for DEP in cp exiv2 mkdir rsync
do
echo -n "Checking dependencies: $DEP - "
if command -v $DEP > /dev/null 2>&1
then
echo -e "OK!"
else
echo "Failed to find $DEP command. Exitting now"
echo -e "\a"
exit 1
fi
done
EXIF_DATA="$(LANG=C exiv2 "${1}")"
if [[ -n "${EXIF_DATA}" ]]
then
echo -e "DEBUG: EXIF_DATA content is\n${EXIF_DATA}\n"
echo -e "Parsing information on file ${1}... "
FILE_EXTENSION=$(echo "$EXIF_DATA" | grep -nE 'File name|Camera model|Image timestamp' | grep ^1 | cut -d\: -f3 | cut -d\. -f2)
MAKER_NAME=$(echo "$EXIF_DATA" | grep -nE 'File name|Camera make|Image timestamp' | grep 'Camera make' | cut -d\: -f3- | cut -d\ -f2-)
DEVICE_NAME=$(echo "$EXIF_DATA" | grep -nE 'File name|Camera model|Image timestamp' | grep 'Camera model' | cut -d\: -f3- | cut -d\ -f2-)
FILE_YEAR=$(echo "$EXIF_DATA" | grep -nE 'File name|Camera model|Image timestamp' | grep 'Image timestamp' | cut -d\: -f3- | cut -d\ -f2- | cut -d\: -f1)
FILE_MONTH=$(echo "$EXIF_DATA" | grep -nE 'File name|Camera model|Image timestamp' | grep 'Image timestamp' | cut -d\: -f3- | cut -d\ -f2- | cut -d\: -f2)
FILE_DAY=$(echo "$EXIF_DATA" | grep -nE 'File name|Camera model|Image timestamp' | grep 'Image timestamp' | cut -d\: -f3- | cut -d\ -f2- | cut -d\: -f3 | cut -d\ -f1)
FILE_HOUR=$(echo "$EXIF_DATA" | grep -nE 'File name|Camera model|Image timestamp' | grep 'Image timestamp' | cut -d\: -f3- | cut -d\ -f3- | cut -d\: -f1)
FILE_MINUTE=$(echo "$EXIF_DATA" | grep -nE 'File name|Camera model|Image timestamp' | grep 'Image timestamp' | cut -d\: -f3- | cut -d\ -f3- | cut -d\: -f2)
FILE_SECOND=$(echo "$EXIF_DATA" | grep -nE 'File name|Camera model|Image timestamp' | grep 'Image timestamp' | cut -d\: -f3- | cut -d\ -f3- | cut -d\: -f3)
for INFORMATION in FILE_EXTENSION MAKER_NAME DEVICE_NAME FILE_YEAR FILE_MONTH FILE_DAY FILE_HOUR FILE_MINUTE FILE_SECOND
do
echo -n "Now parsing ${INFORMATION}: "
if [[ -z $(eval "echo \${$INFORMATION}") ]]
then
echo "FAILED. Variable \$${INFORMATION} is empty"
echo -e "\a"
exit 1
else
echo "OK!"
fi
done
else
echo -e "No EXIF data found on file ${1}"
echo -e "\a"
exit 1
fi
export LAST_DEST_DIR="${DEST_DIR}/${MAKER_NAME}/${DEVICE_NAME}/${FILE_YEAR}/${FILE_MONTH}/${FILE_DAY}"
echo -n "Creating final destination dir ${LAST_DEST_DIR}: "
if mkdir -p "${LAST_DEST_DIR}"
then
echo -e "OK!"
else
echo -e "FAILED. Exitting now"
echo -e "\a"
exit 1
fi
export FILE_NAME_SHORT="${FILE_HOUR}-${FILE_MINUTE}-${FILE_SECOND}.${FILE_EXTENSION}"
#export FILE_NAME_FULL="${DEVICE_NAME}-${FILE_YEAR}-${FILE_MONTH}-${FILE_DAY}-${FILE_HOUR}-${FILE_MINUTE}-${FILE_SECOND}.${FILE_EXTENSION}"
export FILE_NAME_FULL="${DEVICE_NAME// /_}-${FILE_YEAR}-${FILE_MONTH}-${FILE_DAY}-${FILE_HOUR}-${FILE_MINUTE}-${FILE_SECOND}.${FILE_EXTENSION}"
echo -n "Copying file to Destination: "
# if cp -f -v "${1}" "${LAST_DEST_DIR}/${FILE_NAME_FULL}" > /dev/null 2>&1
if rsync -ahuP "${1}" "${LAST_DEST_DIR}/${FILE_NAME_FULL}" > /dev/null 2>&1
then
echo "${LAST_DEST_DIR}/${FILE_NAME_FULL} - full file name copy OK!"
else
echo -e "FAILED. Trying to use a shorter file name"
# if cp -f -v "${1}" "${LAST_DEST_DIR}/${FILE_NAME_SHORT}" > /dev/null 2>&1
if rsync -ahuP "${1}" "${LAST_DEST_DIR}/${FILE_NAME_SHORT}" > /dev/null 2>&1
then
echo "${LAST_DEST_DIR}/${FILE_NAME_SHORT} - short file name copy OK!"
else
echo -e "FAILED! Exitting now"
echo -e "\a"
exit 1
fi
fi
@elisboa
Copy link
Author

elisboa commented May 23, 2021

Manual

Single file usage:

DEST_DIR=/DESTINATION/DIR ./sortfiles-exif.sh FILE.EXT

Batch usage:

DEST_DIR=/DESTINATION/DIR find /ORIGIN/DIR -type f -exec /sortfiles-exif.sh {} \;

@debxp
Copy link

debxp commented May 24, 2021

Legal! Brincando com a parte da captura dos dados:

# Monta um vetor com a saída de 'exiv2'...
data=($(awk '{                                        \
    if ($0 ~ /^File name/)       file = $4;           \
    if ($0 ~ /^Camera model/)    cam = $4;            \
    if ($0 ~ /^Image timestamp/) timestamp = $4" "$5  \
}                                                     \
END {                                                 \
    print file, cam, timestamp                        \
}' <<< "$EXIF_DATA"))

# A data e a hora vêm dos índices 2 e 3...
date=(${data[2]//:/ } ${data[3]//:/ })

# Definindo as variáveis com expansões...
FILE_EXTENSION=${data[0]##*.} # extensão
DEVICE_NAME=${data[1]}        # device
FILE_YEAR=${date[0]}          # ano
FILE_MONTH=${date[1]}         # mês
FILE_DAY=${date[2]}           # dia
FILE_HOUR=${date[3]}          # hora
FILE_MINUTE=${date[4]}        # minuto
FILE_SECOND=${date[5]}        # segundos

Não sei se o padrão da saída é sempre o mesmo, mas foi o que eu deduzi pelos seus cut.

@elisboa
Copy link
Author

elisboa commented Mar 1, 2022

@debxp Quase um ano depois estou começando a realizar testes com sua maravilhosa sugestão, assim que tiver resultados sólidos atualizarei o script. Muito obrigado mesmo! <3

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment