将文件夹中的文件重命名为序号
Posted
技术标签:
【中文标题】将文件夹中的文件重命名为序号【英文标题】:Renaming files in a folder to sequential numbers 【发布时间】:2011-03-13 19:12:22 【问题描述】:我想将目录中的文件重命名为序号。基于文件的创建日期。
例如 sadf.jpg
到 0001.jpg
、wrjr3.jpg
到 0002.jpg
等等,前导零的数量取决于文件的总数(如果不需要,则不需要额外的零)。
【问题讨论】:
我一直在查看 ***.com/questions/880467/…,但我无法让它为我工作。 Linux/Unix 不存储创建日期。 ls -1tr |重命名 -v 's/.*/our $i;if(!$i)$i=1; sprintf("%04d.jpg", $i++)/e' @maXp。这可能无法正确处理特殊字符。也不要在没有--color=never
的情况下使用ls
。
【参考方案1】:
尝试使用循环,let
和 printf
填充:
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
标志可防止自动覆盖现有文件,使用--
可防止mv
将带有破折号的文件名解释为选项。
【讨论】:
您也可以通过printf -v new "%04d.jpg" $a
将值放入变量中。并且((a++))
用于增加变量。此外,这不会按照创建日期顺序执行或最小化 OP 指定的填充。不过需要注意的是,Linux/Unix 不存储创建日期。
需要双引号包裹 mv 才能在我的 bash 环境中工作。 mv "$i" "$new"
可能只是 Cygwin(虽然它的终端行为与普通的 Unix shell 基本相同)但文件名中有空格时似乎有问题。
可能还需要使用mv -- "$i" "$new"
来正确处理以破折号开头的源文件名;事实上,mv
将尝试将此类文件名解析为标志集合。
我一眼就丢失了大约 800 个文件。我认为-i
应该包含在答案中,并且应该相应地重写注释。那会更安全。 :(【参考方案2】:
我喜欢 gauteh 的简单解决方案,但它有一个重要的缺点。在数千个文件上运行时,您可能会收到“参数列表太长”消息(more on this),其次,脚本会变得非常慢。就我而言,在大约 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
了解如何)。
【讨论】:
我修改为使用行号NR
来获得更短的命令。 gawk ' printf "mv %s %04d.jpg\n", $0, NR '
此处存在大量安全漏洞。想想你是否有一个名为$(rm -rf /).jpg
的文件。
在文件名有空格的情况下崩溃。在源文件名周围使用引号。 printf "mv \"%s\" %04d.jpg\n", $0, a++
严格来说,for
循环每个文件不需要 1 秒。从文件系统中获取 36,000 个文件名需要很长时间,然后以相当快的速度循环它们。许多文件系统都存在大型目录的问题,无论您运行哪些精确的命令;但通常,find
会比 shell 通配符更快,因为它必须获取并排序匹配文件列表。
@Pero 您对mv
的使用很危险。除了@CharlesDuffy 的反对意见,如果(在运行脚本之前)已经有一个名为0001.jpg
的文件,例如,会发生什么?它将被处理的第一个文件静默覆盖。其次,如果文件恰好以破折号开头,mv
会将文件名的其余部分视为标志。 cmets 在 gauteh 的回答中提到了这两个问题,以及他们的解决方案:使用 mv -i --
而不是 mv
。除此之外,由于您指出的原因,我同意使用 find
比使用 shell glob 更好。【参考方案3】:
在 OSX 上使用 Pero 的解决方案需要进行一些修改。我用过:
find . -name '*.jpg' \
| awk 'BEGIN a=0 printf "mv \"%s\" %04d.jpg\n", $0, a++ ' \
| bash
注意:反斜杠用于续行
2015 年 7 月 20 日编辑:
合并@klaustopher 的反馈以引用mv
命令的\"%s\"
参数,以支持带空格的文件名。
【讨论】:
和 Pero 的解决方案一样,这里也存在安全漏洞。想想你是否有一个名为$(rm -rf /).jpg
的文件。
谢谢,这行得通。但是你应该引用mv
的第一个参数。如果您有一个名为 some thing.jpg
的文件,您的脚本将失败。这是我用的:find . -name '*.jpg' | awk 'BEGIN a=0 printf "mv \"%s"\ wallpaper-%04d.jpg\n", $0, a++ ' | bash
我可能会使用-maxdepth 1
仅处理当前目录中的 jpg,因为安全总比抱歉好。
如果将管道字符移动到上一行的末尾,则不需要任何反斜杠。
你可以使用ls -1 *.jpg
代替find,否则它不会被排序。或者在 awk 之前添加 |sort|
【参考方案4】:
此脚本将在 Mac OS bash 上按创建日期对文件进行排序。我用它来批量重命名视频。只需更改扩展名和名称的第一部分。
ls -trU *.mp4| awk 'BEGIN a=0 printf "mv %s lecture_%03d.mp4\n", $0, a++ ' | bash
【讨论】:
不要使用这个。像这样重定向到 bash 是一个巨大的安全风险。如果其中一个文件名的格式为blahblah; rm -r * blahblah.mp4
怎么办?
它可能无法处理某些内容,例如空格和特殊字符,也无法处理 ls
颜色。【参考方案5】:
要在所有情况下工作,请为名称中包含空格的文件添加“\”
find . -name '*.jpg' | gawk 'BEGIN a=1 printf "mv \"%s\" %04d.jpg\n", $0, a++ ' | bash
【讨论】:
实际上并未涵盖所有情况。包含文字引号的文件名可能会很容易转义 - 由于您使用的是双引号而不是单引号,因此仍然可以使用像$(rm -rf /)
这样的扩展。
此解决方案确实涵盖了所有内容:***.com/a/65046206/1208218【参考方案6】:
使用“重命名”命令
rename -N 0001 -X 's/.*/$N/' *.jpg
或
rename -N 0001 's/.*/$N.jpg/' *.jpg
【讨论】:
我的rename
(Linux Mint 13) 没有-N
选项。
我可以只为提到重命名命令而投票,我从未听说过它
我很想知道在哪里可以使用 -N 选项获得重命名命令。我的 Ubuntu 14.04 没有。
我喜欢rename
命令,但我从来不知道-N
!谢谢!
有at least three different tools known as rename
。 @Bostrot 发布的链接是另一个重命名工具,似乎@RomanRhrnNesterov 使用了那个。 ¶ 致所有 rename
的用户,作者是 Peder Stray 和 Larry Wall(arch linux 上的包 perl-rename
和 debian/ubuntu 上的包 rename
):您可以自己定义 $N
:perl-rename '$N=sprintf("%04d",++$N); s/.*/$N.jpg/' *.jpg
【参考方案7】:
如果你的rename
不支持-N
,你可以这样做:
ls -1 --color=never -c | xargs rename -n 's/.*/our $i; sprintf("%04d.jpg", $i++)/e'
编辑要从给定的数字开始,您可以使用下面的(有点难看的)代码,只需将 123 替换为您想要的数字即可:
ls -1 --color=never -c | xargs rename -n 's/.*/our $i; if(!$i) $i=123; sprintf("%04d.jpg", $i++)/e'
这会按创建时间顺序列出文件(最新的在前,将-r
添加到 ls 以进行反向排序),然后发送此文件列表以重命名。重命名使用正则表达式中的 perl 代码来格式化和递增计数器。
但是,如果您正在处理带有 EXIF 信息的 JPEG 图像,我建议您使用exiftool
这是来自exiftool documentation,在“重命名示例”下
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
从特定数字开始?
切勿在没有--color=never
的情况下使用ls
,以避免十六进制代码流入管道。
非常好!已添加,谢谢@RoelVandePaar
它是否正确解析文件名中的空格、双引号、反斜杠和 CR?【参考方案8】:
再次使用 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
【讨论】:
不要使用这个。像这样重定向到 bash 是一个巨大的安全风险。如果其中一个文件名的格式为blahblah; rm -r * blahblah.jpg
怎么办?
不,这不包括所有特殊字符和空格。在最佳答案中查看我的 cmets。【参考方案9】:
我遇到了类似的问题,并为此编写了一个 shell 脚本。我决定发布它,尽管已经发布了许多好的答案,因为我认为它可能对某人有所帮助。随意改进它!
numerate
@Gnutt 你想要的行为可以通过键入以下来实现:
./numerate.sh -d <path to directory> -o modtime -L 4 -b <startnumber> -r
如果省略了-r
选项,则只会模拟扩孔(应该有助于测试)。
otion L 描述目标数字的长度(将用前导零填充)
也可以使用选项 -p <prefix>
-s <suffix>
添加前缀/后缀。
如果有人希望文件在编号之前按数字排序,只需删除 -o modtime
选项。
【讨论】:
【参考方案10】:这里是另一个使用“重命名”命令的解决方案:
find -name 'access.log.*.gz' | sort -Vr | rename 's/(\d+)/$1+1/ge'
【讨论】:
恢复前导零:rename 's/(\d+)/sprintf("%04d",$1)+1/ge'
无法按预期工作,因为文件夹的文件名如下:DSC_3451.JPG、DSC_3452.JPG 等。 find -name '*.JPG' |排序-Vr | rename 's/(\d+)/$1+1/ge' 不会修改任何内容
不,您需要-print0
进行查找,并将xargs 与-0
一起使用以使其与特殊字符和空格一起正常工作。【参考方案11】:
a=1
for i in *.jpg; do
mv -- "$i" "$a.jpg"
a=`expr $a + 1`
done
【讨论】:
这能正确处理空格和特殊字符吗?【参考方案12】:假设我们将这些文件放在一个目录中,按创建顺序列出,第一个是最旧的:
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)
对于没有扩展名的文件,会显示警告“使用未初始化的值 […]”;你可以忽略它。
从rename
命令中删除-n
以实际应用重命名。
这个答案的灵感来自Luke’s answer of April 2014。它忽略了 Gnutt 根据文件总数设置前导零数量的要求。
【讨论】:
这对我来说是最有用的答案,主要是因为我想在运行之前干运行操作,还因为我可以通过更改为ls -1tU
来调整创建时间的顺序。它还需要安装rename
,而我没有。
这有问题。参考我的 cmets 上的最佳答案。【参考方案13】:
要重新编号 6000,一个文件夹中的文件,您可以使用 ACDsee 程序的“重命名”选项。
要定义前缀,请使用以下格式:####"*"
然后设置起始编号并按重命名,程序将重命名所有 6000 个文件,并带有序号。
【讨论】:
OP 要求 Unix Bourne Shell 中的一组命令。您正在提议仅在 Windows 环境中运行的商业产品。【参考方案14】:大多数其他解决方案将覆盖已命名为数字的现有文件。如果运行脚本,添加更多文件,然后再次运行脚本,这尤其是一个问题。
此脚本首先重命名现有的数字文件:
#!/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);
【讨论】:
这是否正确处理空格和特殊字符(斜杠)等? 应该可以,如果不行请在这里再次评论【参考方案15】:美在一条线:
ls -v | cat -n | while read n f; do mv -n "$f" "$n.ext"; done
您可以将.ext
更改为.png
、.jpg
等。
【讨论】:
legend :),我在 Windows 上的 git shell 上使用了这个,效果很好! ^^. 效果很好。美在一条线。我添加了 ls -tr get the files by last modified time。 像这样添加 printf:ls | cat -n | while read n f; do mv "$f" `printf "%04d.extension" $n`; done
填充数字为零
警告:您可能需要在 mv 命令中添加 -n
以防止意外覆盖文件。发现这个很难!
把来自 cmets 的一些关于这个答案和其他的好主意放在一起:ls -1prt | grep -v "/$" | cat -n | while read n f; do mv -n "$f" "$(printf "%04d" $n).$f#*."; done
结果: (1) 按修改顺序排序,后面的文件有后面的索引; (2) 忽略目录——而不是递归的; (3) 焊盘索引; (4) 保持原来的扩展。【参考方案16】:
一个非常简单的 bash one 衬里,它保留原始扩展,添加前导零,并且也适用于 OSX:
num=0; for i in *; do mv "$i" "$(printf '%04d' $num).$i#*."; ((num++)); done
http://ubuntuforums.org/showthread.php?t=1355021的简化版
【讨论】:
正是我想要的。我喜欢你可以设置开始索引。 请注意,这不会保留文件的原始顺序。 @RoyShilkrot »不会保留原始订单«是什么意思? bash 和其他 posix shell 中的 Glob 根据系统的语言环境按排序顺序展开。当然,这不会将9.ext
排在11.ext
之前,但其他工具(如ls
)也不会这样做。
不,这可能是一个危险的解决方案,更不用说文件名中的特殊字符和空格将无法正常工作。
这是完美的解决方案.. 跨平台并保持扩展.. 干得好!【参考方案17】:
按时间排序,仅限于 jpg、前导零和基本名称(如果您可能想要一个):
ls -t *.jpg | cat -n | \
while read n f; do mv "$f" "$(printf thumb_%04d.jpg $n)"; done
(全部在一行,没有\
)
【讨论】:
总体而言,此页面上的许多答案都很糟糕,所以也许这不值得特别反对。不过,我不愿支持在脚本中使用ls
的任何内容。
我把这个答案从消极的一面保存下来,虽然它可能很脆弱,但它适用于我的特定用例。
这有问题。将我的 cmets 推荐给评分最高的答案。【参考方案18】:
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
【讨论】:
不要使用这个。像这样重定向到 bash 是一个巨大的安全风险。如果其中一个文件名的格式为blahblah; rm -r * blahblah.jpg
怎么办?只是一个极端的例子。【参考方案19】:
在 OSX 上,从 Homebrew 安装重命名脚本:
brew install rename
那么你就可以很轻松地做到这一点了:
rename -e 's/.*/$N.jpg/' *.jpg
或者添加一个漂亮的前缀:
rename -e 's/.*/photo-$N.jpg/' *.jpg
【讨论】:
这是一个很棒的脚本,它只依赖于 Perl。 brew 仅适用于 mac,但您可以从 github (github.com/ap/rename) 获取它并在 Linux 或 Windows 上使用它。 这对我不起作用。我得到了Global symbol "$N" requires explicit package name (did you forget to declare "my $N"?) at (user-supplied code).
作为 Mac 用户,我很高兴地报告 @TimDanner 链接的重命名应用程序非常便携,就像下载 Zip 存档一样简单,将重命名实用程序放到一个目录中我的 bash 配置文件路径设置为可查看,并且开箱即用。我很惊讶这在 MacPorts 上不可用。我觉得很奇怪,我有一个用于 Rename (2) 的 BSD 手册页,但是当运行 rename 时,它会说不存在命令。去图吧。【参考方案20】:
ls -1tr | rename -vn 's/.*/our $i;if(!$i)$i=1; sprintf("%04d.jpg", $i++)/e'
rename -vn - 移除 n 以关闭测试模式
$i=1; - 控制起始编号
"%04d.jpg" - 控制计数为零 04 并设置输出扩展名 .jpg
【讨论】:
赞成这个答案,因为它只使用本机重命名。我的用例是用从 01 开始的数字替换文件的前两位数字:rename -v -n 's/../our $i;if(!$i)$i=1; sprintf("%02d", $i++)/e' *
不,特殊字符和空格将无法正确处理。更别提ls
颜色输出了。【参考方案21】:
对我来说,这些答案组合非常有效:
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 是一种安全风险。但这对我来说不是这样,因为我使用的是扫描的照片。
【讨论】:
不,空格和特殊字符会成为问题。【参考方案22】:按照命令将所有文件重命名为序列和小写扩展名:
rename --counter-format 000001 --lower-case --keep-extension --expr='$_ = "$N" if @EXT' *
【讨论】:
这是否处理文件名中的空格和特殊字符,如斜杠等?【参考方案23】:这对我有用。 我已经使用了 rename 命令,因此如果任何文件的名称中包含空格,那么 mv 命令不会混淆空格和实际文件。
这里我将所有 jpg 文件的文件名中的空格、'' 替换为 '_'#! /bin/bash rename 'y/ /_/' *jpg #用_替换空格 让 x=0; 对于 *.jpg 中的 i;执行 让 x=(x+1) mv $i $x.jpg 完毕
【讨论】:
在 linux (ubuntu) 上安装重命名,“sudo apt install rename” 这可能会处理空格,但不确定特殊字符。【参考方案24】:现在选择多个文件进行重命名后有一个选项(我在 thunar 文件管理器中看到过)。
-
选择多个文件
检查选项
选择重命名
该特定目录中的所有文件都会出现提示 只需检查类别部分
【讨论】:
【参考方案25】:我花了 3 到 4 个小时来开发这个解决方案,以写一篇关于此的文章: https://www.cloudsavvyit.com/8254/how-to-bulk-rename-files-to-numeric-file-names-in-linux/
if [ ! -r _e -a ! -r _c ]; then echo 'pdf' > _e; echo 1 > _c ;find . -name "*.$(cat _e)" -print0 | xargs -0 -t -I bash -c 'mv -n "" $(cat _c).$(cat _e);echo $[ $(cat _c) + 1 ] > _c'; rm -f _e _c; fi
这适用于任何类型的文件名(空格、特殊字符),方法是使用正确的 \0
转义 find
和 xargs
,您可以通过将 echo 1
增加到任何其他来设置起始文件命名偏移量喜欢就加号。
在开始时设置扩展名(此处为pdf
)。它也不会覆盖任何现有文件。
【讨论】:
【参考方案26】:find . | grep 'avi' | nl -nrz -w3 -v1 | while read n f; do mv "$f" "$n.avi"; done
find .
将显示文件夹和子文件夹中的所有文件。
grep 'avi'
将过滤所有带有 avi 扩展名的文件。
nl -nrz -w3 -v1
将显示从 001 002 等开始的序列号,后跟文件名。
while read n f; do mv "$f" "$n.avi"; done
会将文件名更改为序列号。
【讨论】:
以上是关于将文件夹中的文件重命名为序号的主要内容,如果未能解决你的问题,请参考以下文章