批量重命名文件


25

我有很多文件:

10.3.100.179_01_20161018_230014_5335.jpg
10.3.100.179_01_20161018_231514_0814.jpg
10.3.100.179_01_20161018_233014_5706.jpg
10.3.100.179_01_20161018_234514_0896.jpg
10.3.100.179_01_20161018_230114_5395.jpg
10.3.100.179_01_20161018_231614_1145.jpg
10.3.100.179_01_20161018_233114_6047.jpg
10.3.100.179_01_20161018_234614_0547.jpg
10.3.100.179_01_20161018_230114_5492.jpg
10.3.100.179_01_20161018_231614_1264.jpg
10.3.100.179_01_20161018_233114_6146.jpg
10.3.100.179_01_20161018_234614_0658.jpg
10.3.100.179_01_20161018_230214_5630.jpg
10.3.100.179_01_20161018_231714_7135.jpg

我想使用以下格式重命名:

10.4.100.135_01_20161013131108389_TIMING.jpg
10.4.100.135_01_20161013131111390_TIMING.jpg
10.4.100.135_01_20161013131114401_TIMING.jpg
10.4.100.135_01_20161013131117431_TIMING.jpg
10.4.100.135_01_20161013131120418_TIMING.jpg
10.4.100.135_01_20161013131123461_TIMING.jpg
10.4.100.135_01_20161013131126511_TIMING.jpg

它需要删除_in时间戳并添加_TIMING



5
请在您的问题中使用一致的示例。好像您想替换10.3.100.17910.4.100.135。那是您想要的,还是您只想从时间中删除_TIMING_
terdon

3
提醒人们注意日期的iso8601标准(对文件名和日志条目均适用)的好时机^^因此,也许您应该重新考虑将其重命名为:YYYY-MM-DDThh:mm:ss.mmm(例如:您的第一个文件将变为:( 10.4.100.135_01_2016-10-13T13:11:08.389_TIMING.jpg然后甚至可以删除“ TIMING”,因为它现在看起来很像日期和小时(毫秒),尤其是在标准变得更普及时。T是标准的一部分,而I长大后喜欢它(并且取出它打破了标准的^^)
Olivier Dulac

@OlivierDulac我不建议:在文件名中使用。我相信Windows不支持它。
贾斯汀

@贾斯汀的好点。标准建议删除它以获取文件名。我提供了文件内版本
Olivier Dulac

Answers:


38

安装renameutilsqmv与您喜欢的文本编辑器一起使用。

qmv将所有名称加载到编辑器中,并在保存并关闭时将更改应用于实际文件。如果更改不一致(例如,两个文件具有相同的名称),它将中止而不触摸任何内容。它还可以正确处理循环重命名。

我通常这样做:

$ qmv -f do

因此它只显示一列名称(执行:仅目标位置)。外观如下:

质量

如果将它与SublimeText,Atom或Visual Studio Code的多个游标结合使用,则它将成为批量重命名的非常好用且功能强大的工具。例如,对于Atom,您可以这样做EDITOR="atom -w" qmv -f do


1
欢迎问问Ubuntu!太酷了!
αғsнιη

只需将其签名即可!它。;)
J. Allan

2
哇,不错的工具和不错的GIF动画。伟大的第一答案,欢迎您!:)
字节指挥官

1
感谢@KasiyA插入图像,并感谢其他所有人的正面评价。
ateijelo

1
@kasperd是的,它会警告重命名计划包含错误,并打开一个交互式控制台,您可以在其中执行进一步的操作。
ateijelo

27

使用rename...

rename -n 's/^([0-9]+\.[0-9]\.[0-9]+\.[0-9]+_[0-9]+_)([0-9]+)_([0-9]+)_([0-9]+)\.jpg/$1$2$3$4_TIMING\.jpg/' *

有了-n这将输出什么回事,不做任何更改的事情:

rename(10.3.100.179_01_20161018_230014_5335.jpg, 10.3.100.179_01_201610182300145335_TIMING.jpg)
rename(10.3.100.179_01_20161018_231514_0814.jpg, 10.3.100.179_01_201610182315140814_TIMING.jpg)
rename(10.3.100.179_01_20161018_233014_5706.jpg, 10.3.100.179_01_201610182330145706_TIMING.jpg)
rename(10.3.100.179_01_20161018_234514_0896.jpg, 10.3.100.179_01_201610182345140896_TIMING.jpg)

如果看起来正确,请移除 -n

$ rename 's/^([0-9]+\.[0-9]\.[0-9]+\.[0-9]+_[0-9]+_)([0-9]+)_([0-9]+)_([0-9]+)\.jpg/$1$2$3$4_TIMING\.jpg/' *
$ ls
10.3.100.179_01_201610182300145335_TIMING.jpg  10.3.100.179_01_201610182330145706_TIMING.jpg
10.3.100.179_01_201610182315140814_TIMING.jpg  10.3.100.179_01_201610182345140896_TIMING.jpg

解释...

  • s/something/something_else/ 搜索并替换
  • ^ 名称的开头(锚定)
  • [0-9] 任何数字
  • + 一个或多个以上字符
  • \.文字.(不\匹配任何字符)
  • () 保留这部分
  • $1$2$3$3 返回对之前匹配并保持不变的事物的引用 ()

注意:*命令末尾的匹配当前目录中的所有可见文件。如有必要,请使用更合适的水珠。


2
在某些发行版中,此命令的使用方式为prename(p表示perl,因为第一个arg是perl表达式)
Peter Cordes

12

mmv 可以按照以下步骤进行操作:

mmv '*_*_*_*_*.jpg' '#1_#2_#3#4#5_TIMING.jpg'

10.3.100.179_01_20161018_230014_5335.jpg 10.3.100.179_01_201610182300145335_TIMING.jpg

#1,#2,#3,...在这里将每个引用到匹配的'*'。

它甚至更短:

mmv '*_*_*.jpg' '#1#2#3_TIMING.jpg'

9

另一种rename方法:

$ rename -n 's/(.*)_(.*)_(.*)\./$1$2$3_TIMING./' *
10.3.100.179_01_20161018_230014_5335.jpg -> 10.3.100.179_01_201610182300145335_TIMING.jpg
10.3.100.179_01_20161018_230114_5395.jpg -> 10.3.100.179_01_201610182301145395_TIMING.jpg
10.3.100.179_01_20161018_230114_5492.jpg -> 10.3.100.179_01_201610182301145492_TIMING.jpg
10.3.100.179_01_20161018_230214_5630.jpg -> 10.3.100.179_01_201610182302145630_TIMING.jpg
10.3.100.179_01_20161018_231514_0814.jpg -> 10.3.100.179_01_201610182315140814_TIMING.jpg
10.3.100.179_01_20161018_231614_1145.jpg -> 10.3.100.179_01_201610182316141145_TIMING.jpg
10.3.100.179_01_20161018_231614_1264.jpg -> 10.3.100.179_01_201610182316141264_TIMING.jpg
10.3.100.179_01_20161018_231714_7135.jpg -> 10.3.100.179_01_201610182317147135_TIMING.jpg
10.3.100.179_01_20161018_233014_5706.jpg -> 10.3.100.179_01_201610182330145706_TIMING.jpg
10.3.100.179_01_20161018_233114_6047.jpg -> 10.3.100.179_01_201610182331146047_TIMING.jpg
10.3.100.179_01_20161018_233114_6146.jpg -> 10.3.100.179_01_201610182331146146_TIMING.jpg
10.3.100.179_01_20161018_234514_0896.jpg -> 10.3.100.179_01_201610182345140896_TIMING.jpg
10.3.100.179_01_20161018_234614_0547.jpg -> 10.3.100.179_01_201610182346140547_TIMING.jpg
10.3.100.179_01_20161018_234614_0658.jpg -> 10.3.100.179_01_201610182346140658_TIMING.jpg

如果这似乎按您希望的那样工作,请删除-n


5

您也可以使用以下内容。首先备份您的文件,然后尝试以下操作:

find . -name "*.jpg" -type f -print0| while read -d $'\0' file
do
    #extension="${file##*.}"
    newfilename=$(echo "${file%.*}" | sed 's/\(.*\)_\(.*\)_/\1\2/')
    mv "$file" "$newfilename""_TIMING.jpg"
done

sed 's/\(.*\)_\(.*\)_/\1\2/')删除_时间戳记中的字符。

例如:

user@host$ ls -lart
total 8
drwxrwxr-x 6 user user 4096 Oct 21 10:21 ..
-rw-rw-r-- 1 user user    0 Oct 21 10:30 10.3.100.179_01_20161018_230014_5335.jpg
-rw-rw-r-- 1 user user    0 Oct 21 10:30 10.3.100.179_01_20161018_231514_0814.jpg
-rw-rw-r-- 1 user user    0 Oct 21 10:30 10.3.100.179_01_20161018_233014_5706.jpg
-rw-rw-r-- 1 user user    0 Oct 21 10:30 10.3.100.179_01_20161018_234514_0896.jpg
-rw-rw-r-- 1 user user    0 Oct 21 10:30 10.3.100.179_01_20161018_230114_5395.jpg
-rw-rw-r-- 1 user user    0 Oct 21 10:30 10.3.100.179_01_20161018_231614_1145.jpg
-rw-rw-r-- 1 user user    0 Oct 21 10:30 10.3.100.179_01_20161018_233114_6047.jpg
-rw-rw-r-- 1 user user    0 Oct 21 10:30 10.3.100.179_01_20161018_234614_0547.jpg
-rw-rw-r-- 1 user user    0 Oct 21 10:30 10.3.100.179_01_20161018_230114_5492.jpg
-rw-rw-r-- 1 user user    0 Oct 21 10:30 10.3.100.179_01_20161018_231614_1264.jpg
-rw-rw-r-- 1 user user    0 Oct 21 10:30 10.3.100.179_01_20161018_233114_6146.jpg
-rw-rw-r-- 1 user user    0 Oct 21 10:30 10.3.100.179_01_20161018_234614_0658.jpg
-rw-rw-r-- 1 user user    0 Oct 21 10:30 10.3.100.179_01_20161018_230214_5630.jpg
-rw-rw-r-- 1 user user    0 Oct 21 10:30 10.3.100.179_01_20161018_231714_7135.jpg
drwxrwxr-x 2 user user 4096 Oct 21 10:30 .

user@host$ find . -name "*.jpg" -type f -print0 | while read -d $'\0' file
> do
>  newfilename=$(echo "${file%.*}" | sed 's/\(.*\)_\(.*\)_/\1\2/')
>  mv $file $newfilename"_TIMING.jpg"
> done

10:35:20 t $ ls -lart
total 8
drwxrwxr-x 6 user user 4096 Oct 21 10:21 ..
-rw-rw-r-- 1 user user    0 Oct 21 10:30 10.3.100.179_01_201610182300145335_TIMING.jpg
-rw-rw-r-- 1 user user    0 Oct 21 10:30 10.3.100.179_01_201610182315140814_TIMING.jpg
-rw-rw-r-- 1 user user    0 Oct 21 10:30 10.3.100.179_01_201610182330145706_TIMING.jpg
-rw-rw-r-- 1 user user    0 Oct 21 10:30 10.3.100.179_01_201610182345140896_TIMING.jpg
-rw-rw-r-- 1 user user    0 Oct 21 10:30 10.3.100.179_01_201610182301145395_TIMING.jpg
-rw-rw-r-- 1 user user    0 Oct 21 10:30 10.3.100.179_01_201610182316141145_TIMING.jpg
-rw-rw-r-- 1 user user    0 Oct 21 10:30 10.3.100.179_01_201610182331146047_TIMING.jpg
-rw-rw-r-- 1 user user    0 Oct 21 10:30 10.3.100.179_01_201610182346140547_TIMING.jpg
-rw-rw-r-- 1 user user    0 Oct 21 10:30 10.3.100.179_01_201610182301145492_TIMING.jpg
-rw-rw-r-- 1 user user    0 Oct 21 10:30 10.3.100.179_01_201610182316141264_TIMING.jpg
-rw-rw-r-- 1 user user    0 Oct 21 10:30 10.3.100.179_01_201610182331146146_TIMING.jpg
-rw-rw-r-- 1 user user    0 Oct 21 10:30 10.3.100.179_01_201610182346140658_TIMING.jpg
-rw-rw-r-- 1 user user    0 Oct 21 10:30 10.3.100.179_01_201610182302145630_TIMING.jpg
-rw-rw-r-- 1 user user    0 Oct 21 10:30 10.3.100.179_01_201610182317147135_TIMING.jpg
drwxrwxr-x 2 user user 4096 Oct 21 10:35 .

1
这是最好的解决方案。当然,Zanna的灵魂对于两个文件来说是完美的,但是由于globbing是由shell执行的,因此它们的解决方案可能在大量文件上失败(命令字符串太长)。
rexkogitans '16

@rexkogitans:如果您使用的是现代Linux系统(即Ubuntu的任何版本),则命令行长度的限制为数MB。如果有问题,您可以使用find -maxdepth 1 -exec rename ... {} +该命令将当前目录列表批量添加到重命名的命令行中。(添加-name *.jpg或您想要的任何内容)。这比执行fork + execs sedmv每个文件名的shell循环要快得多,而不仅仅是重命名系统调用。(您可以摆脱sed使用bash内置的regex东西的麻烦,但是分叉mv仍然很慢。)
Peter Cordes

2

您可能已经完成了,但是这里有一个(简单的)所有bash解决方案:
“简单... bash解决方案”是矛盾的吗?

#!/bin/bash

#loop through all files ending in .jpg
for f in *.jpg;
do

    #cut out everything to the timestamp
    firsthalf=${f%_*_*_*}

    #get from the timestamp on
    lasthalf=${f#*_*_}

    #remove (all) underscores from timestamp
    #note the 2 forward slashes...
    lasthalf=${lasthalf//_/}

    #get our extension
    ext=${lasthalf##*.}

    #now we can remove the extension
    lasthalf=${lasthalf%.*}

    #rename the file
    #change `mv` to `echo` if you want to do a trial run first...
    mv "$f" "${firsthalf}_${lasthalf}_TIMING.${ext}"

done;

PS:循环中的逻辑已使用示例文件名之一进行了测试。通过了


1
最好将bash regex与[[ $f ~= (.*)_(.*)_(.*)_(.*)\.jpg ]]; newname=${BASH_REMATCH[1]${BASH_REMATCH:2:4}TIMING.jpg或一起使用。(完全未经测试,可能有误,但总体思路是捕获组进入BASH_REMATCH阵列。)
Peter Cordes

@PeterCordes:这是一个好点!我从未使用过(bash)捕获组,并且说实话,bash不是我尝试使用它们的第一语言。(我认为这bash是一种丑陋的语言。)不过,这是一个很好的解决方案,它教会了我一些荣誉。
J. Allan

是的,使用纯bash进行大量文本处理的主要原因是编写快速完成的制表符完成功能时。它给“丑陋的代码”一词带来了全新的含义……
彼得·科德斯

@PeterCordes:我明白你的意思,尽管认为代码并不“丑陋”。可能不是您提供的2行解决方案,但是就我而言,这并不难阅读。加上评论得很好...
J. Allan

我说的是bash完成代码通常很难看(或至少很难看懂)。实际上,它实际上并不丑陋,只是有些费力(例如,通过传递变量名称并让被调用者使用printf -v "$3" ...其名称为in的变量来完成bash中ref的args传递$3)。拆开整个命令行并将其放回在一起很难跟踪/调试,至少我在尝试清理/修复错误时以这种方式找到了它。参见github上的代码
Peter Cordes

1

如果可以使用GUI,则建议使用pyRenamer

它存在于大多数发行版中,例如Ubuntu中:

sudo apt-get install pyrenamer

它可以满足您的所有需求。

  • 它可以使用模式,添加或禁止显示文本。
  • 重命名照片时可以访问EXIF数据,因此您可以根据日期/时间等生成图案。
  • 重命名音乐文件时可以使用一些元数据。
  • 而且,它具有预览功能,可以防止某些难以恢复的错误。

致低级投票人...解释为什么?OP没有指定GUI是否为选项。我看到大多数答案都来自控制台/脚本方式,但是许多用户会喜欢GUI解决方案。也许pyRenamer有一些我不知道的缺陷。无论如何,我想知道拒绝投票的原因。
jrierab

可能我还建议使用Thunar批量重命名器,以实现快速的交互式GUI方法。
托尼·马丁

@TonyMartin这应该是有疑问的评论,这与答案无关
Sergiy Kolodyazhnyy

0

这里是你的生内置 find + xargs+ sed+ mvoneliner(爱oneliners):

find . -name "*.jpg" -print0 | sort -z | xargs -0 sh -c 'for filename; do mv "$filename" $(echo "${filename}" | sed "s/\([0-9]\{8\}\)_\([0-9]\{6\}\)_\([0-9]\{4\}\)/\1\2\3_TIMING/g"); done' sh

说明:

  • find . -name "*.jpg" | sort | xargs sh -c <command> sh :列出当前目录中的所有JPEG,然后为每个目录执行一个shell命令(排序是可选的,但是如果您在某处登录,则可以使操作更简洁)

  • -print0-z-0:它是好习惯,用二进制单独项目0标化文件名时,以避免在最中间的空格(不是你的情况下,虽然)问题

  • mv "$filename" $(echo "${filename}" | sed "s/\([0-9]\{8\}\)_\([0-9]\{6\}\)_\([0-9]\{4\}\)/\1\2\3_TIMING/g");(在反斜杠sed的正则表达式不利于它的可读性,但它简单的),通过与他们的连续级联加上该更换的8个+ 6个+ 4位数字的下划线separeted序列中的每个文件重命名_TIMING的事情(\i是一个逆向引用的i-正则表达式组)。


参考:Xargs - man sed

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.