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

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-18 13:27:01  来源:igfitidea点击:

How retrieve the creation date of photos with a script

bashdirectoryexifphotos

提问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 exiftoolfound 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 $IMGFILEis 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