【问题标题】:How retrieve the creation date of photos with a script如何使用脚本检索照片的创建日期
【发布时间】:2015-11-10 18:50:19
【问题描述】:

我想做的是重新组织我的相机胶卷文件夹中的文件。使用创建日期,我想根据年/月格式使用它们的创建日期将它们放入文件夹中。

在这个答案中,他们解释了如何制作文件夹并组织它们: 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\}\)$@/\1-\2-\3@')"
    mv "$dir" "$newdir"
    rmdir "$(dirname $dir)"
    rmdir "$(dirname $(dirname $dir))"
done

但它没有解决如何获取创建日期,也许我应该从 EXIF 数据中获取元数据。怎么办?

【问题讨论】:

  • 你可能需要安装一些工具如exiv2 exiv2.org

标签: bash directory exif photos


【解决方案1】:

根据 exiftool 手册页'Renaming examples'

exiftool '-Directory<DateTimeOriginal' -d %Y/%m/%d "$dir"

如果只需要复制,还有一个选项:

exiftool -o . '-Directory<DateTimeOriginal' -d %Y/%m/%d "$dir"

除了文件被复制而不是移动之外,与上面的效果相同。

【讨论】:

  • 请注意,目录是在您当前的目录中创建的,而不是作为要处理的参数给出的目录。
【解决方案2】:

我已经编写了一个 bash 脚本来直接从我的 iphone/ipad 复制文件,并根据图像创建日期将它们复制到目标驱动器上的文件夹中。我使用了一个名为exiftool 的程序,位于http://www.sno.phy.queensu.ca/~phil/exiftool/

对于给定的图像,我将创建日期时间提取到一个数组中

DATEBITS=( $(exiftool -CreateDate -FileModifyDate -DateTimeOriginal "$IMGFILE" | awk -F: '{ print $2 ":" $3 ":" $4 ":" $5 ":" $6 }' | sed 's/+[0-9]*//' | sort | grep -v 1970: | cut -d: -f1-6 | tr ':' ' ' | head -1) )

其中$IMGFILE 是图像文件的路径。然后,您可以使用

访问年、月、日等
YR=${DATEBITS[0]}
MTH=${DATEBITS[1]}
DAY=${DATEBITS[2]}
HR=${DATEBITS[3]}
MIN=${DATEBITS[4]}
SEC=${DATEBITS[5]}

然后创建存储图像文件所需的目录很简单

【讨论】:

  • 还是卡住了?这是其余的。显然根据需要修改目标。这将获取当前目录中的所有文件并将它们排序到year/month/file 结构中:for file in *; do if [ ! -d "$file" ]; then DATEBITS=( $(exiftool -CreateDate -FileModifyDate -DateTimeOriginal "$file" | awk -F: '{ print $2 ":" $3 ":" $4 ":" $5 ":" $6 }' | sed 's/+[0-9]*//' | sort | grep -v 1970: | cut -d: -f1-6 | tr ':' ' ' | head -1) ); YR=${DATEBITS[0]}; MTH=${DATEBITS[1]}; DAY=${DATEBITS[2]}; HR=${DATEBITS[3]}; MIN=${DATEBITS[4]}; SEC=${DATEBITS[5]}; mkdir $YR/$MTH &amp;&amp; mv $file $_; fi; done
【解决方案3】:

从 1997 年开始,我一直致力于整理 14,000 张照片。这是一只熊,因为并非所有相机都是数码相机,尤其是早期的相机。我在图像文件中使用了“CreateDate”标签。

如果可能,我编写了以下 BASH 脚本来执行基于 EXIF 数据的排序。它首先查找 EXIF 'CreateDate' 标签。如果找到,它会使用它。如果不是,它会查找文件名的前 8 个字符以查看它们是否是有效日期(ANDROID 等)。如果两个测试都不是阳性,它会查找 EXIF 'FileModifyDate' 标记,这可能不准确。如果找到 EXIF 'CreateDate',日期前缀 (YYYMMDD-) 将添加到文件名中(如果它不存在),然后将其移动到相应的目录中。如果所有三个测试都失败,则该文件将被单独保留以供用户干预。

如果您很幸运,并且相机支持它,并且摄影师启用了它,那么日期可能会为您印在图像上。我不得不以这种方式对许多照片进行排序,因此请务必查看未处理的照片以及使用 EXIF 'FileModifyDate' 排序方法的照片。

另外,如果你发现你有一些柯达 PCD 图片文件,你可以像这样使用 ImageMajick 的“转换”:

convert $OrigFileName[$SUFX] -colorspace RGB "$(basename $OrigFileName .pcd).jpg"

然而,ImageMajick 并不总是将所有标签复制到新图像文件,但您可以使用 EXIFTOOL 将标签传输到新图像文件,如下所示:

exiftool -tagsFromFile $OrigFileName $(basename $OrigFileName .pcd).jpg

代码:

#! /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 '\r\033[K')"
RED="$(echo -e '\033[1;31m')"
GRN="$(echo -e '\033[1;32m')"
YEL="$(echo -e '\033[1;33m')"
BLU="$(echo -e '\033[1;34m')"
MAG="$(echo -e '\033[1;35m')"
CYN="$(echo -e '\033[1;36m')"
WHT="$(echo -e '\033[1;37m')"
NML="$(echo -e '\033[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,${#1} M=$2,${#2} D=$3,${#3}" >/dev/stderr
  if ([ "$1" -ge "1950" ] && [ "$1" -le "2050" ]) || \
  ([ "$2" -ge "01" ] && [ "$2" -le "12" ]) || \
  ([ "$3" -ge "01" ] && [ "$3" -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        = $1"
  echo "FILE      = $2"
  echo "EXT       = $3"
  echo "FN_WD     = $4"
  echo "DATE      = $5"
  echo "YEAR      = $6"
  echo "MONTH     = $7"
  echo "DAY       = $8"
  echo "ValidDate = $(IsValidDate $6 $7 $8)"
  echo "NOTE      = $9"
  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 $4'} | \
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 $3}')
    # 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 $3}')
        # 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

【讨论】:

    【解决方案4】:

    一直在为相同或类似的问题而苦恼。
    Exiftool 是一个强大的东西,但是它有一些局限性,并不能真正解决文件重复问题。

    这是我在脚本中使用的

    # EXIFSubSecCreateDateParser extracts EXIF metadata: the year, month, day, hour, minute, second, subsecond,
    # and generates date and note
    EXIFSubSecCreateDateParser() {
      # Define a variable and pass the arguments
      EXIF_OUTPUT="${1}"
      # Substitute dots with a common colon delimiter
      EXIF_OUTPUT_SUBSTITUTE="${EXIF_OUTPUT//./:}"
      # Define delimiter
      DELIMITER=":"
      # Concatenate the delimiter with the main string
      DELIMITED_EXIF_OUTPUT="${EXIF_OUTPUT_SUBSTITUTE}${DELIMITER}"
      # Split the text based on the delimiter
      EXIF_OUTPUT_ARRAY=()
      while [[ "${DELIMITED_EXIF_OUTPUT}" ]]; do
        EXIF_OUTPUT_ARRAY+=( "${DELIMITED_EXIF_OUTPUT%%${DELIMITER}*}" )
        DELIMITED_EXIF_OUTPUT="${DELIMITED_EXIF_OUTPUT#*${DELIMITER}}"
      done
      # Assign the array values to the corresponding variables
      YEAR="${EXIF_OUTPUT_ARRAY[0]}"
      MONTH="${EXIF_OUTPUT_ARRAY[1]}"
      DAY="${EXIF_OUTPUT_ARRAY[2]}"
      HOUR="${EXIF_OUTPUT_ARRAY[3]}"
      MINUTE="${EXIF_OUTPUT_ARRAY[4]}"
      SECOND="${EXIF_OUTPUT_ARRAY[5]}"
      SUBSECOND="${EXIF_OUTPUT_ARRAY[6]}"
      DATE="${YEAR}:${MONTH}:${DAY}"
    }
    
    # Attempting to extract EXIF metadata from the file to an array.
    EXIF_EXTRACT=( $(exiftool -s -f -SubSecCreateDate -CreateDate -Model "${WIPSortedFileAbsolutePath}" | awk '{print $3":"$4}') )
    
    # Assigning the array values to variables
    EXIF_SubSecCreateDate_OUTPUT="${EXIF_EXTRACT[0]}"  
    EXIF_CreateDate_OUTPUT="${EXIF_EXTRACT[1]}"  
    EXIF_Model_OUTPUT="${EXIF_EXTRACT[2]}"  
    
    # Setting Target Directory structure with TargetDirectoryStructure
    DestinationStructure="${YEAR}/${MONTH}/${DAY}"
    
    # Setting Filename format
    FormatedFileName="${MODEL}-${YEAR}${MONTH}${DAY}-${HOUR}${MINUTE}${SECOND}-${SUBSECOND}.${NormalisedFileExtension}"
    
    # Moving the file to the Desination File Path
    mv "${File}" "${DestinationPath}/${DestinationStructure}/${FormatedFileName}"
    

    我找到了一些答案,但零碎的解决方案还远远不够。我最终以Johnny Quest's script 为基础编写了自己的东西。

    不管怎样,看看https://github.com/ivang-coder/Neatly-Sorted
    它可能会为您的努力提供一些想法。

    【讨论】:

      猜你喜欢
      • 2017-10-19
      • 1970-01-01
      • 1970-01-01
      • 2021-05-08
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多