我无法评论这个旧帖子,
但它的评论似乎正是我所需要的,所以我开始了一个新帖子,我希望形式不错。
我明白代码的作用,从 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
可以相应地重命名文件。
请访问链接页面以获取完整详细信息,并访问其手册页以获取全套选项。