重命名文件夹中的文件为序号


230

我想将目录中的文件重命名为连续数字。基于文件的创建日期。

例如sadf.jpgto 0001.jpgwrjr3.jpgto 0002.jpg等等,前导零的数目取决于文件的总数(如果不需要,则不需要额外的零)。


我一直在寻找stackoverflow.com/questions/880467/…,但我无法为我工作。
Gnutt

1
Linux / Unix不存储创建日期。
暂停,直到另行通知。

1
ls -1tr | 重命名-v's /.*/我们的$ i; if(!$ i){$ i = 1;} sprintf(“%04d.jpg”,$ i ++)/
e'– maXp

Answers:


313

尝试使用循环letprintf进行填充:

a=1
for i in *.jpg; do
  new=$(printf "%04d.jpg" "$a") #04 pad to length of 4
  mv -i -- "$i" "$new"
  let a=a+1
done

使用该-i标志可防止自动覆盖现有文件。


4
您也printf -v new "%04d.jpg" ${a}可以将值放入变量中。并((a++))增加变量。另外,这不会按照创建日期的顺序进行操作,也不会最小化OP指定的填充。但是,应该注意,Linux / Unix不存储创建日期。
暂停,直到另行通知。

3
需要使用双引号将mv换行,以便在我的bash环境中工作。mv“ $ {i}”“ $ {new}”
Gary Thomann

2
可能只是Cygwin(尽管它的终端行为与普通的Unix shell大致相同),但是当文件名中有空格时,似乎出现了问题。
Geesh_SO

2
可能还需要使用mv -- "$i" "$new"正确处理以破折号开头的源文件名。mv照原样,将尝试解析诸如标志集合之类的文件名。
Charles Duffy 2014年

2
我一眼就丢失了约800个文件。我认为-i应该将其包含在答案中,并相应地重写注释。这样会更安全。:(
KrIsHnA

269

美女合一:

ls -v | cat -n | while read n f; do mv -n "$f" "$n.ext"; done 

您可以更改.ext.png.jpg等等。


4
legend :),我在Windows上的git shell上使用了它,效果很好!^^。
K. Mr.16.24

4
效果很好。美女合一。我添加了ls -tr通过上次修改时间来获取文件。
Ranjith Siji

32
像这样添加printf:ls | cat -n | while read n f; do mv "$f" `printf "%04d.extension" $n`; done填充数字为零
Seweryn Niemiec

8
警告:您可能需要添加-n到mv命令以防止意外覆盖文件。很难发现这一点!
伊恩·丹佛斯

4
从对这个答案的评论中收集一些很棒的主意,以及其他一些意见: ls -1prt | grep -v "/$" | cat -n | while read n f; do mv -n "${f}" "$(printf "%04d" $n).${f#*.}"; done 结果:(1)按修改顺序排序,后面的文件带有后面的索引;(2)忽略目录-而不是递归的;(3)填充索引;(4)保持原始扩展名。
豪尔赫

63

我喜欢gauteh的解决方案,因为它简单易用,但它有一个重要的缺点。当在成千上万个文件上运行时,您可能会收到“参数列表过长”的消息(有关更多信息),其次,脚本会变得非常慢。就我而言,在大约36.000个文件上运行它,脚本移动了大约。每秒一件!我不太确定为什么会这样,但是我从同事那里得到的规则是find是你的朋友”

find -name '*.jpg' | # find jpegs
gawk 'BEGIN{ a=1 }{ printf "mv %s %04d.jpg\n", $0, a++ }' | # build mv command
bash # run that command

为了计数项目和构建命令,使用了gawk。请注意主要区别。默认情况下find,在当前目录及其子目录中搜索文件,因此,请确保在必要时仅在当前目录中进行搜索(man find以了解操作方法)。


7
我修改为将行号NR用于较短的命令。gawk '{ printf "mv %s %04d.jpg\n", $0, NR }'
Apiwat Chantawibul

12
这里存在大量的安全漏洞。考虑一下您是否有一个名为的文件$(rm -rf /).jpg
Charles Duffy 2014年

感谢您指出查尔斯。您能提出一个安全的解决方案吗?
beibei2 2014年

2
如果文件名包含空格,则会分解。在源文件名周围使用引号。printf“ mv \”%s \“%04d.jpg \ n”,$ 0,a ++
baskin

1
for回路不考虑每个文件1秒,严格地说。从文件系统中获取36,000个文件名,然后合理快速地遍历它们,需要花费很长时间。许多文件系统都存在大型目录问题,无论您运行的是哪种精确命令。但通常find会比Shell通配符更快,因为它必须获取并排序匹配文件列表。
Tripleee

30

使用“重命名”命令

rename -N 0001 -X 's/.*/$N/' *.jpg

要么

rename -N 0001 's/.*/$N.jpg/' *.jpg

32
我的rename(Linux Mint 13)没有-N选择。
路加H

我可以投票赞成重命名命令,我从未听说过
user907860 2015年

8
我很想知道在哪里可以使用-N选项获得重命名命令。我的Ubuntu 14.04没有它。
史蒂芬·亨宁森

1
我喜欢rename命令,但我从来不知道-N!谢谢!
Dan Lecocq '17

1
被称为至少有三个不同的工具rename。@Bostrot发布的链接是另一个重命名工具,似乎@RomanRhrnNesterov使用了该工具。¶对于renamePeder Stray和Larry Wall的所有用户(perl-renamearch Linux上的软件包rename和debian / ubuntu上的软件包):您可以定义$N自己:perl-rename '$N=sprintf("%04d",++$N); s/.*/$N.jpg/' *.jpg
Socowi

30

在OSX上使用Pero解决方案需要进行一些修改。我用了:

find . -name '*.jpg' \
| awk 'BEGIN{ a=0 }{ printf "mv \"%s\" %04d.jpg\n", $0, a++ }' \
| bash

注意:反斜杠用于继续行

编辑2015年7月20日: 合并@klaustopher的反馈以引用命令的\"%s\"参数,mv以支持带空格的文件名。


3
像Pero的解决方案一样,这里也存在安全漏洞。考虑一下您是否有一个名为的文件$(rm -rf /).jpg
Charles Duffy 2014年

谢谢,这有效。但是您应该引用的第一个参数mv。如果您有一个名为ie的文件,则some thing.jpg脚本将失败。这就是我所使用的:find . -name '*.jpg' | awk 'BEGIN{ a=0 }{ printf "mv \"%s"\ wallpaper-%04d.jpg\n", $0, a++ }' | bash
klaustopher

我可能会-maxdepth 1只在当前目录中的jpgs上工作,因为安全比后悔好。
PeterPerháč16年

如果将竖线字符移动到上一行的末尾,则不需要任何反斜杠。
Tripleee

您可以使用ls -1 *.jpg而不是查找,否则将不会进行排序。或添加|sort|之前AWK
JPT

28

一个非常简单的bash one衬里,可以保留原始扩展名,添加前导零,并且还可以在OSX中使用:

num=0; for i in *; do mv "$i" "$(printf '%04d' $num).${i#*.}"; ((num++)); done

http://ubuntuforums.org/showthread.php?t=1355021的简化版本


正是我想要的。我喜欢您可以设置开始索引。
Jack Vial

2
请注意,这不会保留文件的原始顺序
罗伊·希克罗

@RoyShilkrot您的意思是» 将不会保留原始顺序 «?bash和其他posix外壳中的globs根据系统的区域设置按排序顺序扩展。当然,它不会9.ext在之前进行排序11.ext,但是其他工具(例如ls)也不会进行排序。
Socowi

11

要在所有情况下都可以工作,请在名称中带有空格的文件前加上\“

find . -name '*.jpg' | gawk 'BEGIN{ a=1 }{ printf "mv \"%s\" %04d.jpg\n", $0, a++ }' | bash

3
实际上并不涵盖所有情况。包含文字双引号的文件名可以轻易转义-并且由于您使用的是双引号而不是单引号,$(rm -rf /)因此仍喜欢使用扩展名。
Charles Duffy 2014年

11

如果您rename不支持-N,则可以执行以下操作:

ls -1 -c | xargs rename -n 's/.*/our $i; sprintf("%04d.jpg", $i++)/e'

编辑要以给定的数字开头,可以使用下面的代码(看起来有些难看),只需将123替换为所需的数字即可:

ls -1 -c | xargs rename -n 's/.*/our $i; if(!$i) { $i=123; } sprintf("%04d.jpg", $i++)/e'

这按创建时间顺序列出文件(最新的,添加 -r到ls进行反向排序),然后发送此文件列表进行重命名。重命名使用正则表达式中的perl代码来格式化和递增计数器。

但是,如果您要处理带有EXIF信息的JPEG图像,我建议 exiftool

这来自exiftool文档的 “重命名示例”下

   exiftool '-FileName<CreateDate' -d %Y%m%d_%H%M%S%%-c.%%e dir

   Rename all images in "dir" according to the "CreateDate" date and time, adding a copy number with leading '-' if the file already exists ("%-c"), and
   preserving the original file extension (%e).  Note the extra '%' necessary to escape the filename codes (%c and %e) in the date format string.

如何使用来从一个特定的数字开始rename

6

在OSX上,从Homebrew安装重命名脚本:

brew install rename

然后,您可以非常轻松地做到这一点:

rename -e 's/.*/$N.jpg/' *.jpg

或添加一个不错的前缀:

rename -e 's/.*/photo-$N.jpg/' *.jpg

3
那是一个很棒的脚本,它仅取决于Perl。brew仅适用于macs,但您可以从github(github.com/ap/rename)获取它,并在Linux或Windows上使用它。
蒂姆·丹纳

3
这对我不起作用。我知道了Global symbol "$N" requires explicit package name (did you forget to declare "my $N"?) at (user-supplied code).
安东尼·钟

作为Mac用户,我很高兴地报告@TimDanner链接的重命名应用程序是超级可移植的,就像下载Zip存档一样简单,将重命名实用程序放到我的bash个人资料路径设置为可查看的目录中,并且开箱即用。我很惊讶MacPorts上没有此功能。我觉得很奇怪,我有一个BSD重命名(2)联机帮助页,但是运行重命名时会说不存在命令。去搞清楚。
adamlogan

2

跟随命令重命名所有文件以序列和小写扩展名:

rename --counter-format 000001 --lower-case --keep-extension --expr='$_ = "$N" if @EXT' *

1

我有一个类似的问题,因此写了一个shell脚本。我决定发布它,而不管已经发布了许多好的答案,因为我认为这可能对某人有所帮助。随时进行改进!

计算

@Gnutt可以通过键入以下命令来实现所需的行为:

./numerate.sh -d <path to directory> -o modtime -L 4 -b <startnumber> -r

如果-r忽略该选项,则扩孔将仅被模拟(对测试很有帮助)。

选项L描述了目标编号的长度(将用前导零填充),也可以在选项中添加前缀/后缀-p <prefix> -s <suffix>

如果有人希望在编号之前对文件进行数字排序,则只需删除该-o modtime选项即可。


1
a=1

for i in *.jpg; do
 mv -- "$i" "$a.jpg"
 a=`expr $a + 1`
done

1

让我们假设我们在目录中按创建顺序列出了这些文件,第一个是最旧的:

a.jpg
b.JPG
c.jpeg
d.tar.gz
e

然后ls -1cr精确输出上面的列表。然后,您可以使用rename

ls -1cr | xargs rename -n 's/^[^\.]*(\..*)?$/our $i; sprintf("%03d$1", $i++)/e'

哪个输出

rename(a.jpg, 000.jpg)
rename(b.JPG, 001.JPG)
rename(c.jpeg, 002.jpeg)
rename(d.tar.gz, 003.tar.gz)
Use of uninitialized value $1 in concatenation (.) or string at (eval 4) line 1.
rename(e, 004)

对于没有扩展名的文件,显示警告“使用未初始化的值[…]”。您可以忽略它。

-nrename命令中删除以实际应用重命名。

此答案受卢克(Luke)2014年4月的回答启发。它忽略了Gnutt要求根据文件总数设置前导零的数目的要求。


这对我来说是最有用的答案,主要是因为我想在运行op之前先对其进行试运行,还因为我可以通过更改ls -1tU为创建时间来调整订单。它还需要rename安装,而我没有。
antonyh

1

再次使用Pero解决方案,几乎无需修改,因为 find不需要它将遍历目录树中的订单项存储在目录条目中。(在大多数情况下)这在同一台计算机上每次运行都将保持一致,并且如果没有删除,则本质上将是“文件/目录创建顺序”。

但是,在某些情况下,您需要获得一些逻辑顺序,例如按名称,此示例中使用了该顺序。

find -name '*.jpg' | sort -n | # find jpegs
gawk 'BEGIN{ a=1 }{ printf "mv %s %04d.jpg\n", $0, a++ }' | # build mv command
bash # run that command 

3
不要使用这个。像这样重定向到bash会带来巨大的安全风险。如果文件名之一为格式blahblah; rm -r * blahblah.jpg怎么办?
xhienne

1

按时间排序,限制为jpg,前导零和基名(以防万一,如果需要的话):

ls -t *.jpg | cat -n |                                           \
while read n f; do mv "$f" "$(printf thumb_%04d.jpg $n)"; done

(全部一行,不带\


按照宏伟的计划,此页面上的许多答案都太可怕了,因此也许这不是特别值得推荐的答案。不过,我会犹豫是否要ls在脚本中使用任何内容。
三月

我从消极的角度保留了这个答案,尽管它可能很脆弱,但它适用于我的特定用例。
维尔(Ville)

1
ls -1tr | rename -vn 's/.*/our $i;if(!$i){$i=1;} sprintf("%04d.jpg", $i++)/e'

重命名-vn-删除n以退出测试模式

{$ i = 1;} -控制开始号码

“%04d.jpg” -控制计数为零04并设置输出扩展名.jpg


支持此答案,因为它仅使用本机重命名。我的使用案例是从01开始的数字替换文件的前两个数字:rename -v -n 's/../our $i;if(!$i){$i=1;} sprintf("%02d", $i++)/e' *
minterior

1

对我来说,答案的组合非常有效:

ls -v | gawk 'BEGIN{ a=1 }{ printf "mv %s %04d.jpg\n", $0, a++ }' | bash
  • ls -v 有助于正确订购1 10 9:1 9 10顺序,避免jpg JPG jpeg的文件扩展名问题
  • gawk 'BEGIN{ a=1 }{ printf "mv %s %04d.jpg\n", $0, a++ }'用4个字符和前导零重新编号。通过避免使用mv,我不会无意间尝试使用相同的数字来覆盖已经存在的任何内容。
  • bash 执行

请注意@xhienne所说的内容,将未知内容传递给bash有安全隐患。但这不是我的情况,因为我正在使用扫描的照片。


0

您也可以使用ls

ls *.JPG| awk 'BEGIN{ a=0 }{ printf "mv %s gopro_%04d.jpg\n", $0, a++ }' | bash

5
请参阅mywiki.wooledge.org/ParsingLs,以及其他类似损坏的解决方案上的安全漏洞的描述。
Charles Duffy 2014年

1
不要使用这个。像这样重定向到bash会带来巨大的安全风险。如果文件名之一为格式blahblah; rm -r * blahblah.JPG怎么办?
xhienne

0

其他大多数解决方案将覆盖已经命名为数字的现有文件。如果运行脚本,添加更多文件,然后再次运行脚本,则这尤其成问题。

此脚本首先重命名现有的数字文件:

#!/usr/bin/perl

use strict;
use warnings;

use File::Temp qw/tempfile/;

my $dir = $ARGV[0]
    or die "Please specify directory as first argument";

opendir(my $dh, $dir) or die "can't opendir $dir: $!";

# First rename any files that are already numeric
while (my @files = grep { /^[0-9]+(\..*)?$/ } readdir($dh))
{
    for my $old (@files) {
        my $ext = $old =~ /(\.[^.]+)$/ ? $1 : '';
        my ($fh, $new) = tempfile(DIR => $dir, SUFFIX => $ext);
        close $fh;
        rename "$dir/$old", $new;
    }
}

rewinddir $dh;
my $i;
while (my $file = readdir($dh))
{
    next if $file =~ /\A\.\.?\z/;
    my $ext = $file =~ /(\.[^.]+)$/ ? $1 : '';
    rename "$dir/$file", sprintf("%s/%04d%s", $dir, ++$i, $ext); 
}

0

此oneliner列出当前目录中的所有文件,并以相反的顺序按创建时间戳排序(意味着最旧的文件位于开头),并根据文件数量的要求自动重命名为尾随零。文件扩展名将被保留。

多年来,我通常只有一个文件夹用于存放手机图片和电影。应用此命令,我的图片和电影就可以在电视或存档上以正确的顺序进行幻灯片放映了。

请注意,如果文件名冲突,则将丢失文件。因此,首先将其重命名为类似的名称temp001.jpg,然后执行最终文件名。

DIGITS=$(ls | wc -l | xargs | wc -c | xargs); ls -tcr | cat -n | while read n f; do mv "$f" "$(printf "%0${DIGITS}d" $n).${f##*.}"; done

1
ls最好不要避免运行一次,而应该运行两次,但是我没有深入研究它。
Tripleee

1.如果我有意提议单线,为什么以后要更改它?像我这样的许多用户更喜欢复制粘贴一个班轮来完成任务。对于其他喜欢逐行复制的人,此线程中还有其他答案。2.最初的问题是“前导零的数量取决于文件的总数”,并且这是第一个完成的ls,因此这就是为什么需要两个的原因。3.这样的命令是单发命令,并不意味着要包含在脚本中,因此人们偏爱
单线

1
抱歉,没有意识到您认为这很重要。对我来说,能够阅读代码大大胜过将其复制/粘贴为一行的能力。我还没有发现Bash在跨多行粘贴时会有问题的环境,但是我可能忽略了某些东西。
三人房

0

这对我有用。
我使用过重命名命令,以便任何文件的名称中都包含空格,那么mv命令不会在空格和实际文件之间造成混淆。

在这里,我将所有jpg文件的文件名中的空格'''替换为'_'
#!/ bin / bash
重命名'y / / _ /'* jpg#用_替换空格
令x = 0;
为* .jpg中的我做
    令x =(x + 1)
    mv $ i $ x.jpg
完成

在Linux(ubuntu)上安装重命名,“ sudo apt安装重命名”
rishang bhavsar

0

如今,选择多个文件进行重命名后有一个选项(我在thunar文件管理器中已经看到)。

  1. 选择多个文件
  2. 检查选项
  3. 选择重命名

该特定目录中的所有文件都会出现提示,只需检查类别部分即可


-1

该脚本将在Mac OS bash上按创建日期对文件进行排序。我用它来批量重命名视频。只需更改扩展名和名称的第一部分即可。

ls -trU *.mp4| awk 'BEGIN{ a=0 }{ printf "mv %s lecture_%03d.mp4\n", $0, a++ }' | bash

1
不要使用这个。像这样重定向到bash会带来巨大的安全风险。如果文件名之一为格式blahblah; rm -r * blahblah.mp4怎么办?
xhienne

-1

这是另一个使用“重命名”命令的解决方案:

find -name 'access.log.*.gz' | sort -Vr | rename 's/(\d+)/$1+1/ge'

恢复零位:rename 's/(\d+)/sprintf("%04d",$1)+1/ge'
Camille Goudeseune

对于包含以下名称的文件的文件夹,此文件夹无法正常工作:DSC_3451.JPG,DSC_3452.JPG等。find -name'* .JPG'| 排序-Vr | 重命名's /(\ d +)/ $ 1 + 1 / ge'不做任何修改
Tiberiu C.

-2

Pero的回答把我带到了这里:)

我想重命名相对于时间的文件,因为图像查看器未按时间顺序显示图像。

ls -tr *.jpg | # list jpegs relative to time
gawk 'BEGIN{ a=1 }{ printf "mv %s %04d.jpg\n", $0, a++ }' | # build mv command
bash # run that command

2
不要使用这个。像这样重定向到bash会带来巨大的安全风险。如果文件名之一为格式blahblah; rm -r * blahblah.jpg怎么办?只是一个极端的例子。
xhienne


-3

要对6000个文件重新编号,可以使用ACDsee程序的“重命名”选项。

要定义前缀,请使用以下格式: ####"*"

然后设置起始编号,然后按重命名,程序将使用顺序编号重命名所有6000个文件。


1
OP在Unix Bourne Shell中要求一组命令。您正在提议仅在Windows环境中运行的商业产品。
xhienne
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.