给定EXIF数据,如何重命名照片?


14

假设我有一堆照片,所有照片都带有正确的EXIF信息,并且这些照片是随机命名的(因为我遇到了问题)。我有一个小程序jhead,它给出以下输出:

$ jhead IMG_9563.JPG

File name    : IMG_9563.JPG
File size    : 638908 bytes
File date    : 2011:02:03 20:25:09
Camera make  : Canon
Camera model : Canon PowerShot SX210 IS
Date/Time    : 2011:02:03 20:20:24
Resolution   : 1500 x 2000
Flash used   : Yes (manual)
Focal length :  5.0mm  (35mm equivalent: 29mm)
CCD width    : 6.17mm
Exposure time: 0.0080 s  (1/125)
Aperture     : f/3.1
Focus dist.  : 0.29m
ISO equiv.   : 125
Exposure bias: -1.67
Whitebalance : Manual
Light Source : Daylight
Metering Mode: pattern
Exposure Mode: Manual

现在,我需要以以下格式重命名文件夹中的所有照片:

001.JPG
002.JPG
003.JPG
...

次要编号是较旧的图像,最大编号是较新的图像。

我的脚本编写不太好,所以我需要帮助。

我认为bash脚本就足够了,但是如果您觉得更舒服,可以编写python脚本。

我以为是这样的:

$ mv IMG_9563.JPG `jhead IMG_9563.JPG | grep date`

但我不知道如何一次对所有文件执行此操作。


我不明白次要/最大的句子和前面的例子。你能澄清一下吗?
maxschlepzig 2011年

次要/最大文件名是第一步。因为,一旦我用它们代表较旧和较新的方式命名了文件,我就可以轻松地使用另一个程序将其重命名为001.jpg,002.jpg等,尽管最好使用另一个脚本来实现。
Tomas

“重新命名表”将是ls *.JPG | wc > rename然后我必须使用重命名为XXX.JPG的脚本
Tomas

不好意思,不是wc,我忘了一个按名称订购。
Tomas

该命令是排序。
Tomas

Answers:


10

您可以使用for循环(在shell / shell脚本中)对所有文件执行以下操作:

for i in *.JPG; do
  j=`jhead "$i" | grep date | sed 's/^File date[^:]\+: \(.\+\)$/\1/'`.jpg
  echo mv -i "$i" "$j"
done

这只是一个非常基本的轮廓。echo确认一切正常后,请删除。


谢谢。现在,格雷普·乌德尔给我File date : 2011:02:03 20:25:09。如何仅过滤第二列?
Tomas

因此,我只将文件重命名为20:25:09
Tomas

@Tomas,更新了答案-如果您真的只想要时间(那么碰撞呢?),您当然必须修改正则表达式。
maxschlepzig 2011年

j=`jhead "$i" | grep date | sed 's/.* //'`.jpg代替?
frabjous 2011年

@maxshlepzig:谢谢,您错过了'“ .jpg”之前的内容
Tomas

28

只是在这里发现jhead可以为您完成所有工作!:)

jhead -autorot -nf%Y-%m-%d_%H-%M-%S *.jpg

7
是! 但请注意该特定的格式字符串,因为它将为在同一秒钟内拍摄的两个文件提供相同的名称。%i(或%03i具体来说),将按照原始问题的要求给出序列号。将两者结合起来可能不是一个坏主意。
mattdm

只是为了回应mattdm的评论-“ jhead”手册建议它将自动在复制品(相同的时间戳)后附加一个额外的数字或字母(1、2、3或a,b,c等)。
约翰U

0

如果有人需要更复杂的重命名,例如在文件名中包含关键的暴露值,这是我的小脚本。它重命名JPEG文件是这样的:NightSky_2014.08.27_22.30.05_NX20_F2.8_f20.0mm_20s_ISO800.jpg

#!/bin/bash

for s in *.jpg *.JPG
do
 echo $s
 x=`jhead "$s" | \
 awk 'BEGIN { cmt=""; }
/Camera model/   { c=$4$5$6;} 
/Exposure time:/ { e=$3; 
                   if (e==int(e)) e=int(e); 
                   if (e<1) {e=int(0.5+1/e); e="1T" e "s";} else { e=e "s"; } 
                 }
/ISO equiv./     { iso="ISO" $4; } 
/Focal length/   { f="f" $4; } 
/Date.Time /     { d=$3 "_" $4; gsub(":",".",d); }
/Aperture /      { ap=$3; gsub("f/","F",ap); } 
/Comment  /      { cmt=$3 "_"; }
END { print cmt d "_" c "_" ap "_" f "_" e "_" iso ".jpg"; }'`

 echo mv $s $x
 mv $s $x
 echo =====
done

0

我喜欢由maxschlepzig发布的代码,但是在输出方面仍然有困难。

问题是结果文件名中的空格(日期字符串和时间字符串之间)。尽管对于使用GUI的任何人来说都是微不足道的,但它使命令行上的文件处理更加困难。

在这里,“ sed”命令已实质上更改为四个单独的“ sed”操作,以支持先前的整体论点。为了适合自己,以下内容还将文件更改为普通644权限。

for i in *.JPG ; do
  chmod 644 $i
  j=`jhead "$i" | grep ^Date/Time | sed -e 's/^Date\/Time[ ]\+: //;s/:/-/g;s/ /_/g':/-/g;s/ /_/g'`.jpg
  echo mv -i "$i" "$j"
  # mv -i "$i" "$j"
done

2
欢迎使用Stack Exchange。(1)我了解sed得很好,所以我基本上了解您正在尝试做什么。但是,我们在Stack Exchange上的目标不是分发鱼三明治,也不是编写数千个一次性解决方案来解决琐碎的问题。我们的目标是教人们如何钓鱼(即教人们,包括当前的提问者和未来的读者如何解决自己的问题)。为此,如果您解释自己的工作,那么答案会更好。(请不要在评论中回应;请修改您的答案以使内容更清楚。)…(续)
G-Man说'Reinstate

(续)…(2)您的命令失败,因为引号不平衡。请不要发布未经测试的代码。
G-Man说'恢复莫妮卡'

0

因为更容易处理(imho),所以我为自己编写了一个Ruby脚本:

require 'fileutils'

ARGV.each { |file|
  if File.exist?(file) && !File.directory?(file)
    exif = `exiftool "#{file}" | grep -E "(Error|Create Date)"`
    if exif.strip.size > 0
      exif = exif.split("\n")[0].split(/\s+/)
      if exif[0] != "Error"
        # Change the target format here
        filename = exif[3].gsub(":", "-") + " " + 
                   exif[4].gsub(":", ".") + 
                   File.extname(file)
        if filename != file && !File.exist?(filename)
          FileUtils::mv(file, File.dirname(file) + "/" + filename)
        end
      end
    end
  end
}

这是做什么的?

  1. 遍历作为参数传递的所有文件(例如*.JPG)。

    我检查了它是否可以正确处理RAW文件和视频。它应该exiftool可以处理所有问题。

  2. 如果文件不执行任何操作

    • 不存在,
    • 是一个目录,
    • 没有EXIF日期,或者
    • exiftool 报告错误,或者
    • 具有目标文件名的文件已存在。

这使得它非常强大。特别是,没有文件可以像其他一些答案一样消失(无声)。


0

exiv2 将是一种替代的操作方式,它允许使用非常简单的语法:

exiv2是一个用于读取和写入Exif,IPTC,XMP元数据和图像注释的程序,并且可以读取许多供应商makernote标签。该程序可以选择在Exif标记,XMP属性和IPTC数据集之间转换

因此,这将重命名当前文件夹中的所有jpeg:

for i in *.JPG; do exiv2 -v -r '%Y%m%d.%H%M%S.:basename:' rename "$i"; done

如果您还想添加地理信息,则可以使用exivtool

exiftool '-filename<${gpslatitude;} ${gpslongitude} ${datetimeoriginal}' -d "%Y-%m-%d %H.%M.%S%%-c.%%e" *.JPG

0

我喜欢@Kevin的解决方案,因为我也想保留原始名称(避免在同一秒钟内拍摄图像时出现问题),因此这是我的解决方案:

for i in *.JPG; do jhead -nf%Y%m%d_%H%M%S_"$(basename "$i" .JPG)" "$i" ; done

0

首先由新手发布...第一个bash脚本...我喜欢上面的Libor / HalosGhost解决方案,因为它在重命名中包含了更多详细信息。但是经过测试,重复的文件名最终会丢失文件。因此,我在文件名末尾添加了一个计数器标记,以方便参考和防止冲突。我确信这里有人可以对此进行改进,但认为可能会有所帮助。

我很抱歉张贴代码。我在界面上遇到困难,但是如果有人可以指出我正确的做事方式,那就太好了。

#!/bin/bash

y=1
for s in *.jpg *.JPG
do
 echo $s
 x=`jhead "$s" | \
 awk 'BEGIN { cmt=""; }
/Camera model/   { c=$4$5$6;}
/Exposure time:/ { e=$3;
                   if (e==int(e)) e=int(e);
                   if (e<1) {e=int(0.5+1/e); e="1T" e "s";} else { e=e "s"; }
                 }
/ISO equiv./     { iso="ISO" $4; }
/Focal length/   { f="f" $4; }
/Date.Time /     { d=$3 "_" $4; gsub(":","",d); }
/Aperture /      { ap=$3; gsub("f/","F",ap); }
/Comment  /      { cmt=$3 "_"; }
END { print cmt d "_" c "_" ap "_" f "_" e "_" iso "_" ; }'`

 echo mv $s "$x${y}.jpg"
 mv $s "$x${y}.jpg"
 y=$((y+1))
 echo =====
done

谢谢斯蒂芬的编辑。尝试学习
jgroezin
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.