bash 如何使用脚本检索照片的创建日期
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/32062159/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How retrieve the creation date of photos with a script
提问by prab4th
What I want to do is reorganize files in my Camera Roll folder. Using the creation date I want to Put them inside folders according to Year/Month Format using their creation date.
我想要做的是重新组织我的相机胶卷文件夹中的文件。使用创建日期我想根据年/月格式使用它们的创建日期将它们放入文件夹中。
In this answer, they explain how to make folders and organize them: https://stackoverflow.com/a/1314394/4980886
在这个答案中,他们解释了如何制作文件夹并组织它们:https: //stackoverflow.com/a/1314394/4980886
#!/bin/bash
find $PHOTO_DIR -regextype posix-extended -type d -regex '.*/[0-9]{4}/[0-9]{2}/[0-9]{2}$' |
while read dir; do
newdir="$(echo $dir | sed 's@/\([0-9]\{4\}\)/\([0-9]\{2\}\)/\([0-9]\{2\}\)$@/--@')"
mv "$dir" "$newdir"
rmdir "$(dirname $dir)"
rmdir "$(dirname $(dirname $dir))"
done
But it doesn't address how to get the creation date, maybe I should get the metadata from EXIF data. How to do either?
但它没有解决如何获取创建日期,也许我应该从 EXIF 数据中获取元数据。两者都怎么做?
回答by mdn
According to exiftool man page 'Renaming examples'
根据 exiftool 手册页“重命名示例”
exiftool '-Directory<DateTimeOriginal' -d %Y/%m/%d "$dir"
exiftool '-Directory<DateTimeOriginal' -d %Y/%m/%d "$dir"
and if only copying is required, there is an option:
如果只需要复制,还有一个选项:
exiftool -o . '-Directory<DateTimeOriginal' -d %Y/%m/%d "$dir"
exiftool -o . '-Directory<DateTimeOriginal' -d %Y/%m/%d "$dir"
has the same effect as above except files are copied instead of moved.
除了文件被复制而不是移动之外,具有与上述相同的效果。
回答by bhu Boue vidya
i have written a bash script to copy files straight off my iphone/ipad and copy them into folders on a target drive based on image creation date. i use a program called exiftool
found at http://www.sno.phy.queensu.ca/~phil/exiftool/
我已经编写了一个 bash 脚本来直接从我的 iphone/ipad 复制文件,并根据图像创建日期将它们复制到目标驱动器上的文件夹中。我使用了一个称为exiftool
发现在http://www.sno.phy.queensu.ca/~phil/exiftool/
for a given image, i extract the creation datetime into an array using
对于给定的图像,我使用
DATEBITS=( $(exiftool -CreateDate -FileModifyDate -DateTimeOriginal "$IMGFILE" | awk -F: '{ print ":" ":" ":" ":" }' | sed 's/+[0-9]*//' | sort | grep -v 1970: | cut -d: -f1-6 | tr ':' ' ' | head -1) )
where $IMGFILE
is the path to the image file. you can then get access to the year, month, day etc using
哪里$IMGFILE
是图像文件的路径。然后,您可以使用访问年、月、日等
YR=${DATEBITS[0]}
MTH=${DATEBITS[1]}
DAY=${DATEBITS[2]}
HR=${DATEBITS[3]}
MIN=${DATEBITS[4]}
SEC=${DATEBITS[5]}
it is then trivial to create the directory you need to stash the image file in
然后创建您需要存储图像文件的目录是微不足道的
回答by Johnny Quest
I've been working on sorting me mum's 14,000 photos she's been collecting since 1997. It's a bear because not all digital cameras, especially the early ones, used the 'CreateDate' tag in the image files.
我一直在整理我妈妈自 1997 年以来收集的 14,000 张照片。这是一只熊,因为并非所有数码相机,尤其是早期的数码相机,都在图像文件中使用了“CreateDate”标签。
I wrote the following BASH script to perform the sorting based on EXIF data, if possible. It looks for the EXIF 'CreateDate' tag first. If found, it uses it. If not, it looks for the 1st 8 characters of the file name to see if they are a VALID date (ANDROID, etc). If neither tests positive, it looks for the EXIF 'FileModifyDate' tag, which can be inaccurate. If the EXIF 'CreateDate' is found, the date prefix (YYYMMDD-) will be added to the file name (if it doesn't already exist) and then it will be moved into it's appropriate directory. If all three tests fail, the file is left alone for user intervention.
如果可能的话,我编写了以下 BASH 脚本来执行基于 EXIF 数据的排序。它首先查找 EXIF 'CreateDate' 标签。如果找到,它就会使用它。如果不是,则查找文件名的前 8 个字符以查看它们是否为有效日期(ANDROID 等)。如果两者都没有测试为阳性,它会查找 EXIF 'FileModifyDate' 标签,这可能是不准确的。如果找到 EXIF 'CreateDate',日期前缀 (YYYMMDD-) 将被添加到文件名中(如果它不存在),然后它将被移动到相应的目录中。如果所有三个测试都失败,则该文件将单独留待用户干预。
If you're lucky, and the camera supported it, and the photographer enabled it, the date may be imprinted on the image for you. I had to sort MANY photos this way, so be sure to look at the photos that are not processed and those that use the EXIF 'FileModifyDate' method of sorting.
如果您很幸运,并且相机支持它,并且摄影师启用了它,那么日期可能会为您印在图像上。我不得不以这种方式对许多照片进行排序,因此请务必查看未处理的照片以及使用 EXIF 'FileModifyDate' 排序方法的照片。
Also, if you find you have some of those KODAK PCD picture files, you can use ImageMajick's "convert" like so:
此外,如果您发现自己有一些柯达 PCD 图片文件,您可以像这样使用 ImageMajick 的“转换”:
convert $OrigFileName[$SUFX] -colorspace RGB "$(basename $OrigFileName .pcd).jpg"
However, ImageMajick doesn't always copy all the tags to the new image file but you can use EXIFTOOL to transfer the tags to your new image file like so:
但是,ImageMajick 并不总是将所有标签复制到新图像文件中,但您可以使用 EXIFTOOL 将标签传输到新图像文件,如下所示:
exiftool -tagsFromFile $OrigFileName $(basename $OrigFileName .pcd).jpg
Hope this helps.
希望这可以帮助。
Peace and blessings, Johnny Quest
和平与祝福,约翰尼·奎斯特
#! /bin/bash
# This script is used to sort photos. It uses the EXIFTOOL to
# 1st attempt to extract the photo's "CreateDate". If it is
# invalid, then the file name is checked to see if it begins
# with "YYYYMMDD", which is also checked for validity. If the
# prior two checks fail, then the photo's "FileModifyDate" is
# used but can be inaccurate.
# If a valid creation date is found and the file name is NOT
# date-encoded, then the file is renamed with a "YYYYMMDD-"
# prefix.
#=======================================================================
# Revision index:
# 2019-0704: KSV - Created and tested.
#=======================================================================
DEBUG=0 # Debugging
DRYRUN=0 # Do everything but move the files
NOTE="" # Notes
# ANSI COLORS
CRE="$(echo -e '\r3[K')"
RED="$(echo -e '3[1;31m')"
GRN="$(echo -e '3[1;32m')"
YEL="$(echo -e '3[1;33m')"
BLU="$(echo -e '3[1;34m')"
MAG="$(echo -e '3[1;35m')"
CYN="$(echo -e '3[1;36m')"
WHT="$(echo -e '3[1;37m')"
NML="$(echo -e '3[0;39m')"
#=======================================================================
# Functions
#=======================================================================
# Enter with: YEAR, MONTH and DAY
# Returns: 0=invalid date, 1=valid date
# EX: IsValidDate $YEAR $MONTH $DAY
IsValidDate() {
#echo "Parm: Y=,${#1} M=,${#2} D=,${#3}" >/dev/stderr
if ([ "" -ge "1950" ] && [ "" -le "2050" ]) || \
([ "" -ge "01" ] && [ "" -le "12" ]) || \
([ "" -ge "01" ] && [ "" -le "31" ]) ; then
echo "1" # valid date
else
echo "0" # invalid date
fi
}
# Dump debugging info
# EX: $(DumpDebug $FN $FILE $EXT $FN_WD $DATE $YEAR $MONTH $DAY "$NOTE")
DumpDebug() {
#echo "1=${#FN}, 2=${#FILE}, 3=${#EXT}, 4=${#FN_WD}, 5=${#DATE}, 6=${#YEAR}, 7=${#MONTH}, 8=${#DAY}, 9=${#NOTE}" >/dev/stderr
echo "================================"
echo "FN = "
echo "FILE = "
echo "EXT = "
echo "FN_WD = "
echo "DATE = "
echo "YEAR = "
echo "MONTH = "
echo "DAY = "
echo "ValidDate = $(IsValidDate )"
echo "NOTE = "
echo "================================"
}
#=======================================================================
# Script starts here
#=======================================================================
# Use exiftool to find video and photos
#exiftool -filename *.[JjGg][PpIi][GgFf] *.[Jj][Pp][Ee][Gg] *.[Mm][PpOo][Gg4Vv] 2>/dev/null | awk {'print '} | \
find . -maxdepth 1 -type f -iname "*.[JjGg][PpIi][GgFf]" -or \
-iname "*.[Jj][Pp][Ee][Gg]" -or \
-iname "*.[Mm][PpOo][Gg4Vv]" | \
while read FN ; do
FN=$(basename $FN) # strip the leading "./"
if [ -e $FN ] && [ ${#FN} != 0 ] ; then # be sure the file exists!
EXT=${FN##*.} # extract the extension
FILE=${FN%.*} # extract the base file name
# First attempt to see if there is a valid date prefix in the file name.
YEAR=$(echo ${FN:0:4} | egrep -E ^[0-9]+$ ) # insure digits only
MONTH=$(echo ${FN:4:2} | egrep -E ^[0-9]+$ ) # insure digits only
DAY=$(echo ${FN:6:2} | egrep -E ^[0-9]+$ ) # insure digits only
DATE="$YEAR:$MONTH:$DAY" # create a DATE string
# Check the filename's derived date from for validity (not NULL strings)
# and that the date falls within the proper range
if ([ ! -z "${YEAR}" ] && [ ! -z "${MONTH}" ] && [ ! -z "${DAY}" ]) && \
[ $(IsValidDate $YEAR $MONTH $DAY) == 1 ] ; then
if [ $DEBUG == 1 ] ; then echo "ValidDate: $(IsValidDate $YEAR $MONTH $DAY)" ; fi
FN_WD=0 # date prefix exists, do not append the derived date to the filename.
else
FN_WD=1 # append the derived date prefix to the filename.
fi
# Next, attempt to find an EXIF CreateDate from the file, if it exists.
DATE=$(exiftool -s -f -CreateDate $FN | awk '{print }')
# Perform sanity check on correctly extracted EXIF CreateDate
if [ "${DATE}" != "-" ] && [ "${DATE}" != "0000:00:00" ] ; then
# Good date extracted, so extract the year, month and day
# of month from the EXIF info
echo "A valid ${WHT}CreateDate${NML} was found, using it."
YEAR=${DATE:0:4}
MONTH=${DATE:5:2}
DAY=${DATE:8:2}
NOTE="(by CreateDate)"
else
# EXIF CreateDate invalid or not found, so attempt to derive the
# date from the file name.
YEAR=$(echo ${FN:0:4} | egrep -E ^[0-9]+$ ) # insure digits only
MONTH=$(echo ${FN:4:2} | egrep -E ^[0-9]+$ ) # insure digits only
DAY=$(echo ${FN:6:2} | egrep -E ^[0-9]+$ ) # insure digits only
DATE="$YEAR:$MONTH:$DAY" # create a DATE string
# check the extracted date from filename for validity (not NULL strings)
# and that the date falls within the proper range
#if [ -z "${YEAR}" ] || [ -z "${MONTH}" ] || [ -z "${DAY}" ] ; then
if ([ ! -z "${YEAR}" ] && [ ! -z "${MONTH}" ] && [ ! -z "${DAY}" ]) && \
[ $(IsValidDate $YEAR $MONTH $DAY) == 1 ] ; then
echo "A valid ${WHT}FileNameDate${NML} was found, using it."
NOTE="(by file name)"
else
# EXIF CreateDate and FileNameDate extraction failed, so attempt
# to extract the EXIF FileModifyDate from the file, if it exists.
DATE=$(exiftool -s -f -FileModifyDate $FN | awk '{print }')
# Perform sanity check on correctly extracted EXIF FileModifyDate
if [ "${DATE}" != "-" ] && [ "${DATE}" != "0000:00:00" ] ; then
# Good FileModifyDate found, extract the year, month and
# day of month from the EXIF info
echo "A valid EXIF CreateDate and FileNameDate were not found!"
echo " The innacurate ${WHT}FileModifyDate${NML} will be used."
YEAR=${DATE:0:4}
MONTH=${DATE:5:2}
DAY=${DATE:8:2}
NOTE="(!inaccurate! by FileModifyDate)"
FN_WD=0 # date prefix exists, do not append the derived date to the filename.
else
echo "Invalid date retrieved!"
if [ $DEBUG == 1 ] ; then
echo "Length = ${#YEAR}-${#MONTH}-${#DAY}"
fi
echo "Skipping File: $FN..."
echo
fi
fi
fi
# Modify the filename if a valid EXIF CreateDate or FileNameDate was found.
if [ $FN_WD == 0 ] ; then
FILE=${FILE}.${EXT}
else
FILE=${YEAR}${MONTH}${DAY}-${FILE}.${EXT}
fi
# Debug output
if [ $DEBUG == 1 ] ; then DumpDebug $FN $FILE $EXT $FN_WD $DATE $YEAR $MONTH $DAY "$NOTE" ; fi
# We have a date, hopefully a good one, move the file
if [ $DRYRUN == 0 ] ; then
# create the directory structure. Pipe errors to NULL
mkdir -p $YEAR/$MONTH/$DAY >/dev/null 2>&1
# move the file to the appropriate directory
echo " -> Moving $FN to $YEAR/$MONTH/$DAY/$FILE $NOTE"
mv $FN $YEAR/$MONTH/$DAY/$FILE
echo
else
echo "Dryrun: Moving $FN to $YEAR/$MONTH/$DAY/$FILE"
echo
fi
# Clear the variables
FN=""; FILE=""; EXT=""; FN_WD=""; DATE=""; YEAR=""; MONTH=""; DAY=""; NOTE=""
else
echo
echo "File $FN not found!"
echo
fi
done