一次性为数百个文件进行重命名,以便正确排序。

我有一堆文件,都以像1.jpg2.jpg3.jpg等命名,一直到1439.jpg。然而,我的一个项目在字母排序方面出了问题。它通常会按照1.jpg10.jpg11.jpg的顺序排列。 我需要的是一种快速高效地将文件命名为00001.jpg01439.jpg这样的格式的方法。 我应该如何快速有效地完成这个任务?

你所寻找的是"自然排序",也许这个链接可以帮到你:http://askubuntu.com/questions/41390/can-nautilus-use-correct-lexicographic-sort - Fabian Blechschmidt
不是直接回答的答案?ls -v http://unix.stackexchange.com/questions/33909/list-files-sorted-numerically - WernerCD
+1 是因为我在 pyrenamer 中尝试过但未成功。 - Parto
@FabianBlechschmidt,我需要这个程序不是为了nautilus或类似的东西。它是为一个个人项目而设计的。 - Kaz Wolfe
我觉得你考虑过实现自然排序吗?但是我明白,重命名文件相当容易,如果能达到目的就很好 :) - Fabian Blechschmidt
http://stackoverflow.com/questions/55754/bash-script-to-pad-file-names - Ciro Santilli OurBigBook.com
9个回答

Ubuntu自带一个名为rename的脚本。它只是一个小型的Perl脚本,具有许多强大的批量重命名功能,但最好的(在这种情况下)是它能够在替换过程中运行Perl。结果是一个真正简洁的解决方案:
rename 's/\d+/sprintf("%05d", $&)/e' *.jpg
这与其他在这里的printf风格的答案类似,但是所有的处理都由我们来完成。上面的代码适用于一个5位数(包括可变数量的前导零)。 它将搜索并替换找到的第一个数字字符串为带有零填充的版本,并保持文件名的其余部分不变。这意味着您不必太担心扩展名或前缀的问题。 注意:这并不完全可移植。许多发行版使用util-linux软件包中的rename.ul作为默认的rename二进制文件。这是一个明显受限的替代方案(请参阅man rename.ul),它无法理解上述内容。如果您想在不使用Perl的rename的平台上使用此功能,请先了解如何安装它。
这是一个测试工具的例子:
$ touch {1..19}.jpg

$ ls
10.jpg  12.jpg  14.jpg  16.jpg  18.jpg  1.jpg  3.jpg  5.jpg  7.jpg  9.jpg
11.jpg  13.jpg  15.jpg  17.jpg  19.jpg  2.jpg  4.jpg  6.jpg  8.jpg

$ rename 's/\d+/sprintf("%05d", $&)/e' *.jpg

$ ls
00001.jpg  00005.jpg  00009.jpg  00013.jpg  00017.jpg
00002.jpg  00006.jpg  00010.jpg  00014.jpg  00018.jpg
00003.jpg  00007.jpg  00011.jpg  00015.jpg  00019.jpg
00004.jpg  00008.jpg  00012.jpg  00016.jpg

还有一个前缀示例(我们没有做任何不同的事情):

$ touch track_{9..11}.mp3 && ls
track_10.mp3  track_11.mp3  track_9.mp3

$ rename 's/\d+/sprintf("%02d", $&)/e' *.mp3 && ls
track_09.mp3  track_10.mp3  track_11.mp3

如果我是一个Perl程序员,这将是完美的解决方案。非常棒。 - MGP
2它不使用任何perl,只是一个已经用perl编写好的工具。 - Rob
1在这种情况下,它确实涉及到一个Perl命令,但并不是非常复杂。在Perl中,sprintf的行为类似于其他语言中的sprintf - Oli
$& 的意思是什么? - user2740
@user2740 是一个占位变量,用于表示当前文件名。 - Oli
称赞你提到了那些版本有限的发行版。 - Szczepan Hołyszewski

for f in *.jpg ; do if [[ $f =~ [0-9]+\. ]] ; then  mv $f `printf "%.5d" "${f%.*}"`.jpg  ; fi ; done

编辑

解释:

  • if [[ $f =~ [0-9]+\. ]] 确保只有文件名是数字(后跟一个点)的文件被重命名。
  • printf "%.5d" NUMBER 添加前导零。
  • "${f%.*}" 去掉扩展名(.jpg),只保留数字。
  • .jpg 在第二个反引号之后再次添加文件扩展名。

请注意,这仅适用于文件名为数字的文件。对非数字文件进行左填充前导零需要使用不同的格式。

如果您想尝试,请使用以下命令:

for f in *.jpg ; do if [[ $f =~ [0-9]+\. ]] ; then echo mv $f `printf "%.5d" "${f%.*}"`.jpg  ; fi ; done

编辑2

通过确保只重命名数字文件名,使命令更加安全。请注意,任何已存在的文件名为00001.jpg的文件将被覆盖。


这个一行脚本在Ubuntu和其他Linux发行版上“开箱即用”!无需使用perl、python等安装任何额外工具。 - Rohan 'HEXcube' Villoth
也适用于FreeBSD;但有一个注意事项:像5.1.cbz这样的文件会被当作5.cbz处理,并导致覆盖它们。请先将它们移开。 - emk2203

以下是一个Python脚本。 该脚本会在文件名前添加零,直到达到指定的位数。如果文件名已经超过了指定的位数,则不会进行修改。 将不同的扩展名组合在一起进行重命名操作可能会更加方便。要添加扩展名,只需将它们添加到元组中,例如extensions = (".jpg", ".jpeg", ".tiff")。 将文本复制到一个空文件中,保存为rename.py,然后输入文件目录的正确路径(sourcedir),您希望新名称具有的位数(number_ofdigits)以及要重命名的文件扩展名(extensions)。 通过以下命令运行它:
python3 /path/to/script/rename.py
脚本:
#!/usr/bin/python3

import shutil
import os

sourcedir = "/path/to/files"; number_ofdigits = 5; extensions = (".jpg", ".jpeg")

files = os.listdir(sourcedir)
for item in files:
    if item.endswith(extensions):
        name = item.split("."); zeros = number_ofdigits-len(name[0])
        newname = str(zeros*"0")+name[0]+"."+name[1]
        shutil.move(sourcedir+"/"+item, sourcedir+"/"+newname)

编辑:

以下是稍微改进的版本。它会自动确定目录中最长的名称,并在最长名称的长度之前添加前导零。

示例:

1.jpg
12.jpg
123.jpg

变成:

001.jpg
012.jpg
123.jpg
不需要设置数字的位数。
#!/usr/bin/python3

import shutil
import os

sourcedir = "/path/to/files"; extensions = (".jpg", ".jpeg")
files = [(f, f[f.rfind("."):], f[:f.rfind(".")]) for f in os.listdir(sourcedir)if f.endswith(extensions)]
maxlen = len(max([f[2] for f in files], key = len))

for item in files:
    zeros = maxlen-len(item[2])
    shutil.move(sourcedir+"/"+item[0], sourcedir+"/"+str(zeros*"0")+item[0])

在Perl中实现了一个重命名工具,使这个过程变得非常简单。
rename 's/\d+/sprintf("%05d",$&)/e' *.jpg
第一个参数是一个Perl表达式,它会对每个文件名进行求值。

有些机器上的"rename"命令没有正确指向perl-rename,所以我们需要打开perl包管理器cpan并运行cpan1> install File::Rename来安装File::Rename模块。 - SergioAraujo
确实,在Ubuntu 20.04上,可以使用sudo apt install rename进行安装。 - Mats Kindahl

有一个称为pyRenamer的GUI可以做到这一点,可以在软件仓库中找到。安装后启动,选择您的目录,然后在“模式”选项卡上将“重命名文件名模式”设置为“{num5}”,最后点击“重命名”按钮即可。您还可以在重命名之前预览即将发生的变化。

虽然你的回答是有效的,请注意这是一个“shell脚本”部分,意味着我正在寻找一个命令行的答案。另外,你能提供关于这个程序的更多细节吗?比如,{num5}是什么样的模式格式? - Kaz Wolfe

我刚刚发现,只需将所有没有扩展名的编号文件放入一个文件夹中,然后使用Ubuntu FILES图形界面中的“全选”功能,你实际上可以右键点击并将它们全部重命名,只需在[原始文件名]框后面加上“.jpg”即可,非常简单。我感到很惊讶。

如果你的 `rename` 命令不是 perl-rename,你可以使用这段 perl 代码:
foreach (<*.jpg>) { rename $_, sprintf("%03d.jpg", $1) if /^(\d+).jpg/; }
当我们说foreach时,我们可以通过$_引用文件。 但是您可以使用以下命令安装适当的perl-rename
cpan
cpan1> install File::Rename

另一种轻松重命名这些文件的方法是使用 Ranger 文件管理器打开文件夹,选择所有文件,运行 :bulkrename 并使用以下 vim 命令:

:%s/^\d\+/\=printf("%03d", submatch(0))
我也尝试过使用ls + awk。
ls -1 | awk -F. '{printf "%s%s%s%03d.%s\n", "mv ", $0, " ", $1, $2}'
每个字符串或数字都必须与printf函数关联,输出结果将类似于以下内容:
mv 9.jpg 009.jpg
要真正使用这个进行重命名,你必须在末尾添加| sh
ls -1 | awk -F. '{printf "%s%s%s%03d.%s\n", "mv ", $0, " ", $1, $2}' | sh

zsh shell有一个可加载的zmv模块,类似于外部的mmv命令,并且它还支持在其shell glob中使用数字范围<m-n>。因此,例如给定:
 % ls *.mp4
'3 - Ariane Rocket Disaster.mp4'           '81 - Proof of Guarantee (Sketch).mp4'
'39 - Conditions Example.mp4'              '82 - Measured vs. Worst-Case Probability.mp4'
'396 - Execution Path of a Program.mp4'    '86 - Coverage of Random Testing.mp4'
'397 - Computation Tree Example.mp4'       '88 - Intro to Automated Test Generation.mp4'
'398 - Existing Approach I.mp4'            '89 - Outline.mp4'
'399 - Existing Approach II.mp4'           '9 - Program Invariants.mp4'
'400 -  Combined Approach.mp4'             '90 - Korat.mp4'
'401 - An Illustrative Example .mp4'       '91 - The Problem.mp4'
'402 - Computation Tree.mp4'               '92 - An Insight.mp4'
'403 - Computation Tree Solution.mp4'      '94 - Scheme for Representing Shapes.mp4'
'7 - Dynamic Program Analysis.mp4'         '95 - Representing Shapes.mp4'
'78 - Concurrency Bug Depth Solution.mp4'  '96 - Representing Shapes Solution.mp4'
'79 - Cuzz Algorithm.mp4'                  '97 - A Simple Algorithm.mp4'
'8 - Static Program Analysis.mp4'          '98 - Enumerating Shapes.mp4'
'80 - Probabilistic Guarantee.mp4'         '99 - Enumerating Shapes Solution.mp4'
然后一旦模块加载完成
 % autoload -Uz zmv
你可以做
 % zmv -n '(<1-99>) - (*.mp4)' '${(l:3::0:)1} - ${2}'
mv -- '3 - Ariane Rocket Disaster.mp4' '003 - Ariane Rocket Disaster.mp4'
mv -- '39 - Conditions Example.mp4' '039 - Conditions Example.mp4'
mv -- '7 - Dynamic Program Analysis.mp4' '007 - Dynamic Program Analysis.mp4'
mv -- '78 - Concurrency Bug Depth Solution.mp4' '078 - Concurrency Bug Depth Solution.mp4'
mv -- '79 - Cuzz Algorithm.mp4' '079 - Cuzz Algorithm.mp4'
mv -- '8 - Static Program Analysis.mp4' '008 - Static Program Analysis.mp4'
mv -- '80 - Probabilistic Guarantee.mp4' '080 - Probabilistic Guarantee.mp4'
mv -- '81 - Proof of Guarantee (Sketch).mp4' '081 - Proof of Guarantee (Sketch).mp4'
mv -- '82 - Measured vs. Worst-Case Probability.mp4' '082 - Measured vs. Worst-Case Probability.mp4'
mv -- '86 - Coverage of Random Testing.mp4' '086 - Coverage of Random Testing.mp4'
mv -- '88 - Intro to Automated Test Generation.mp4' '088 - Intro to Automated Test Generation.mp4'
mv -- '89 - Outline.mp4' '089 - Outline.mp4'
mv -- '9 - Program Invariants.mp4' '009 - Program Invariants.mp4'
mv -- '90 - Korat.mp4' '090 - Korat.mp4'
mv -- '91 - The Problem.mp4' '091 - The Problem.mp4'
mv -- '92 - An Insight.mp4' '092 - An Insight.mp4'
mv -- '94 - Scheme for Representing Shapes.mp4' '094 - Scheme for Representing Shapes.mp4'
mv -- '95 - Representing Shapes.mp4' '095 - Representing Shapes.mp4'
mv -- '96 - Representing Shapes Solution.mp4' '096 - Representing Shapes Solution.mp4'
mv -- '97 - A Simple Algorithm.mp4' '097 - A Simple Algorithm.mp4'
mv -- '98 - Enumerating Shapes.mp4' '098 - Enumerating Shapes.mp4'
mv -- '99 - Enumerating Shapes Solution.mp4' '099 - Enumerating Shapes Solution.mp4'

在替换变量扩展中,(l:3::0:)是一个修饰符,它使用字符串0将左侧填充到宽度3

如果您对建议的重命名满意,请删除-n标志。


for file in `(find * -maxdepth 1 -type f -name "*.jpg")`     
do    
  mv $file "000"$file    
done
这个方法有点粗糙,因为它没有智能地进行重命名,需要想一个办法解决这个问题。但是它应该能帮助你整理东西。 更新:好吧,你有一个更完整的答案。

2它将1439.jpg重命名为0001439.jpg。 - Avinash Raj
是的,我知道,只是在数字后面填充了额外的零,这样在排序时仍然有效。 - Swarnendu Biswas