用于 EXIF 重命名的 SED 和 REGEX

用于 EXIF 重命名的 SED 和 REGEX

我无法评论这个旧帖子,

如何根据 EXIF 数据重命名照片?

但它的评论似乎正是我所需要的,所以我开始了一个新帖子,我希望形式不错。

我明白代码的作用,从 jhead 通过 grep 和 SED 的管道......

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

我想要一个非常相似的结果,但我想稍微修改一下日期,即。重命名/输出: yyyymmdd-hhmmss 但我无法弄清楚(翻译)SED 正则表达式。我试过

sed 's/^File date[^:]\+: \(\d{4}\):\(\d\d\):\(\d\d\) \(\d\d\):\(\d\d\):\(\d\d\)$/\1\2\3-\4\5\6/'

但我得到的是

File date   :  yyyy:mm:yy hh:mm:ss

我非常想了解 SED 和使其工作的正则表达式,我意识到它对于流编辑来说非常强大。我特别不理解这一部分 [^:] 我认为有时插入符号表示 BOL 就像 $ 表示 EOL ...但是,当我尝试发布此内容并看到其他 SED 帖子时,我(再次?)了解到“^ " 可能意味着“不”,所以 [^:] 意味着“匹配 NOT :”..?但紧接着是:

不管怎样,我迷路了。

答案1

AFAICT,看起来您想将日期字符串中的空格更改为字符-

这实际上非常简单......但是,首先,该 shell 脚本存在一些问题。首先,它使用反引号代替$(and进行命令替换)。其次,它不必要地使用 grep (sed 可以完成 grep 在这里所做的事情)。第三,您想要执行的正则表达式搜索和替换比一步更容易完成两步(首先删除该行的“文件日期”部分,然后修改剩余的日期字符串)。

这是该脚本的改进版本:

for i in *.JPG; do
  j=$(jhead "$i" | sed -n -E '/^File date/ { s/^File date +: +//; s/ /-/p}').jpg
  echo mv -i "$i" "$j"
done

英语:jhead命令的输出通过管道传输到 sed。 sed 选项告诉 sed 不要输出任何行,除非通过(print) 语句-n告知。p-E选项告诉它使用扩展正则表达式(ERE)而不是基本正则表达式(BRE)...这主要是为了我可以使用修饰符+来匹配一个或多个空格。

sed 脚本本身首先检查该行是否以“文件日期”开头。如果是,它将执行一个 sed 命令块(即包含在{和中的两个或多个命令})。

该块中的第一个命令从该行中删除“文件日期”,后跟一个或多个空格、冒号,然后是一个或多个空格。这将导致该行仅包含日期。

第二个命令用破折号更改第一个(也是唯一一个)空格字符-p该命令末尾有一个s///,它告诉 sed 打印修改后的行。

示例运行:

$ ls -l *.JPG
-rw-r--r-- 1 cas cas 1110176 Oct 20 14:04 abc.JPG
-rw-r--r-- 1 cas cas 1132711 Oct 20 14:04 def.JPG
-rw-r--r-- 1 cas cas 1061121 Oct 20 14:04 ghi.JPG


$ for i in *.JPG; do
  j="$(jhead "$i" |sed -n -E '/^File date/ { s/^File date +: +//; s/ /-/p }').jpg"
  echo mv -i "$i" "$j"
done
mv -i abc.JPG 2021:10:20-14:04:08.jpg
mv -i def.JPG 2021:10:20-14:04:09.jpg
mv -i ghi.JPG 2021:10:20-14:04:10.jpg

顺便说一句,这个脚本并不是特别安全。例如,它没有考虑两个不同的 jpeg 文件可以具有完全相同的时间戳这一事实。

像下面这样的东西远非完美,但会更安全/更好:

for i in *.JPG; do
  j="$(jhead "$i" | sed -n -E '/^File date/ { s/^File date +: +//; s/ /-/p }')"

  c=1
  while [ -e "$j-$c.jpg" ] ; do
    let c+=1
  done
  j="$j-$c"

  mv -iv "$i" "$j.jpg"
done

(注意:这个版本实际上重命名了文件,它不仅仅是echo它会做什么。这对于测试是必要的,因为如果不这样做,它就不知道何时增加计数器变量,$c

输出示例:

renamed 'abc.JPG' -> '2021:10:20-14:04:08-1.jpg'
renamed 'def.JPG' -> '2021:10:20-14:04:08-2.jpg'
renamed 'ghi.JPG' -> '2021:10:20-14:04:08-3.jpg'

顺便说一句,如果您可能有超过 9 个具有相同时间戳的 jpeg 文件,您可以使用它printf来确保计数器是两位或三位数字并且以零填充。例如

for i in *.JPG; do
  j="$(jhead "$i" | sed -n -E '/^File date/ { s/^File date +: +//; s/ /-/p }')"

  c=1
  while [ -e "$(printf "%s-%03i.jpg" "$j" "$c")" ] ; do
    let c+=1
  done
  j="$(printf "%s-%03i.jpg" "$j" "$c")"

  mv -iv "$i" "$j"
done


renamed 'abc.JPG' -> '2021:10:20-14:04:08-001.jpg'
renamed 'def.JPG' -> '2021:10:20-14:04:08-002.jpg'
renamed 'ghi.JPG' -> '2021:10:20-14:04:08-003.jpg'

RE:您关于插入符的问题^

在括号表达式之外,它是行首锚点 - 例如^File date匹配“文件日期”仅有的在一行的开头。

在括号表达式内,它否定/反转表达式的含义。例如,其中[A-Z]匹配从 A 到 Z 的所有字符,[^A-Z]匹配以下的所有字符不是A 和 Z 之间。

答案2

为什么要重新发明轮子?

jhead可以选择完全按照您的意愿行事。

-n[格式字符串] 此选项会导致使用 Exif 标头“DateTimeOriginal”字段中的日期信息对文件进行重命名和/或移动 [原文如此!]。

甚至考虑具有相同时间戳的多张照片:

如果目标名称已经存在,则该名称将附加“a”,“b”,“c”等,除非名称以字母结尾,在这种情况下,它将附加“0”,“1” 、“2”等

例子:

jhead -n%Y%m%d-%H%M%S *.JPG

答案3

谢谢全部非常。我担心会问一些愚蠢的问题,但我想学习,所以我就把它们扔在那里。这就是为什么,尽管这可能是在重新发明轮子,但我确实学到了一些东西。就像 Jhead 自己可能已经完成了这一切一样,谢谢 @pLumo ,正是 SED 和(忘记)正则表达式的阴谋让我感到愤怒。经过更多思考,我确实看到 [^:]+ 是search for one or more characters that are NOT ":" (谢谢@cas),遗憾的是我太慢了格罗克之前那个。而且我也不知道 SED 使用 [[:digit:]] 的语法。所以我试图建立的线路看起来像这样

j=`jhead "$i" | grep date | sed 's/^File date[^:]\+: \([[:digit:]]\{4\}\):\([[:digit:]]\{2\}\):\([[:digit:]]\{2\}\) \([[:digit:]]\{2\}\):\([[:digit:]]\{2\}\):\([[:digit:]]\{2\}\)$/\1\2\3-\4\5\6/'`.jpg

@cas在这种情况下是的,我正在更改为空格,但也删除了“:”。通过学习如何让 SED 匹配数字,我可以配置我喜欢的任何格式/模式,而不仅仅是替换分隔符。

我最大的心理障碍似乎来自于有如此多的操作数被转义(我希望这是正确的术语),即。之前的反斜杠..一切!我就是不能格罗克就这样。

您所有的建议都给了我更多的编码工具/技术,我努力做笔记,以便我可以在提出更多新手问题之前找到它们!十分感谢

我发帖后就遇到了一场雷雨,所以即使我找到了办法,我也无法尽快发表回复 - 我必须断开桌面连接,只能使用手机进行一些浏览,对于尝试写一篇文章来说没什么用处不过在手机上。

答案4

请用EXIV2CLI 工具如下:

exiv2 -r "IMG_%Y%m%d_%H%M%S" -F *

如果当前目录包含图像文件。

它可以通过查询图像 EXIF 元数据来做很多事情。特别是, with-r可以相应地重命名文件。

请访问链接页面以获取完整详细信息,并访问其手册页以获取全套选项。

相关内容