在 linux 上修复几千个文件名
Posted
技术标签:
【中文标题】在 linux 上修复几千个文件名【英文标题】:Fixing a few thousands filenames on linux 【发布时间】:2013-02-03 18:50:20 【问题描述】:我使用 ffmpeg 从视频中提取剪辑,遵循此模式 'clip-%4d.png'。
这产生了如下文件:clip-0001.png
、clip-0002.png
等等。
然后,我使用 imagemagick "convert" 对这些图片应用了许多过滤器,它运行了几个小时。
我意识到我的列表顺序在clip-9999.png
之后被破坏了,它变成了clip-10000.png
和clip-40000.png
,成功地破坏了我的剪辑序列。
我想将我的所有剪辑转换为遵循clip-00000.png
、clip-00001.png
到clip-40000.png
的序列。
我可以使用模式 'clip-%5d' 重新启动整个过程,但有人告诉我 rename
实用程序可能会解决我的问题;但是我自己对正则表达式很陌生。
【问题讨论】:
【参考方案1】:在 bash 中使用这个命令:
for file in clip-????.png ; do
mv $file clip-0$file#clip-
done
要检查命令是否正确,请将“mv”替换为“echo mv”以查看将要完成的重命名列表。
【讨论】:
$file//clip-
是一种bashism。由于这是前缀,所以可以使用简单的$file#clip-
(remove-prefix) 并且更便携。
大声笑,很好的manu-fatto,你是最快的,现在想想为什么在这个操作之后,一些文件的名称中仍然会有不同数量的数字:) Q. 作者认为很好,尽管结合了 find + sed 或 awk 会更好。您需要的只是填充表达式,将任何数字填充到带有前导零的字符中的指定长度。
@Jan:我只记得 // 命令……这是最有用的。其他我应该在文档中查看。
@Piotr:我不明白...请告诉我!
@PiotrWadas:正则表达式过于宽松;它会拾取已经存在的 5 位数名称,但不能。更好的正则表达式是'clip-[[:digit:]]4.png'
,它与要映射的名称完全匹配。【参考方案2】:
使用基于 Perl 的 rename
命令
如果你有一个基于 Perl 的 rename
命令,那就很简单了:
rename 's/(\d4)/0$1/' *-????.png
顺便提一下,如果您确实有大约 10,000 个剪辑要重命名,您可能需要使用 xargs
或 find
以避免出现“参数列表太长”的问题。
find . -name 'clip-????.png' -exec rename 's/(\4)/0$1/' +
或:
find . -name 'clip-????.png' -print | xargs rename 's/(\d4)/0$1/'
由于您的名称不包含空格,因此两者都可以。如果需要担心空格,请使用 find
-only 变体,假设您的 find
支持 POSIX 2008 +
表示法到 find
。这可以应用于任何其他答案,但要小心。
我注意到这个 Perl 脚本避免了必须执行 mv
10,000 次,因此它可能超过任何为每个文件重命名执行 mv
的 shell 脚本。对于一次性练习,这可能无关紧要,但当您获得超过 100,000 个剪辑时,这将成为一个更大的问题。
此外,下面的脚本可以选择读取文件名,每行一个,但它会将整个文件名吞入内存,效率不高(但存在于脚本的原始版本中并且已经保留,即使我几乎从未使用过该选项)。假设一台正常的现代机器(比如 1 GiB 的内存,但更少的内存就足够了),只有 10,000 个名称,每个名称长度为 12 个字符,这不会成为问题。所以你也可以使用:
find . -name 'clip-????.png' -print | rename 's/(\d4)/0$1/'
基于 Perl 的 rename
脚本
如果您没有基于 Perl 的 rename
命令,我会使用这个命令。它最初来自骆驼书的第一版,但多年来已经进行了一些修改:
#!/usr/bin/env perl
#
# @(#)$Id: rename.pl,v 1.8 2011/06/03 22:30:22 jleffler Exp $
#
# Rename files using a Perl substitute or transliterate command
use strict;
use warnings;
use Getopt::Std;
my(%opts);
my($usage) = "Usage: $0 [-fnxV] perlexpr [filenames]\n";
my($force) = 0;
my($noexc) = 0;
my($trace) = 0;
die $usage unless getopts('fnxV', \%opts);
if ($optsV)
printf "%s\n", q'RENAME Version $Revision: 1.8 $ ($Date: 2011/06/03 22:30:22 $)';
exit 0;
$force = 1 if ($optsf);
$noexc = 1 if ($optsn);
$trace = 1 if ($optsx);
my($op) = shift;
die $usage unless defined $op;
if (!@ARGV)
@ARGV = <STDIN>;
chop(@ARGV);
for (@ARGV)
if (-e $_ || -l $_)
my($was) = $_;
eval $op;
die $@ if $@;
next if ($was eq $_);
if ($force == 0 && -f $_)
print STDERR "rename failed: $was - $_ exists\n";
else
print "+ $was --> $_\n" if $trace;
print STDERR "rename failed: $was - $!\n"
unless ($noexc || rename($was, $_));
else
print STDERR "$_ - $!\n";
【讨论】:
【参考方案3】:你可以这样做:
for f in clip-[0-9][0-9][0-9][0-9].png; do mv $f `echo $f | sed 's/clip-/clip-0/'`; done
注意:要在不实际执行任何操作的情况下进行测试,请将 mv
替换为 echo mv
。
【讨论】:
10,000 个sed
命令; 10,000 个mv
命令;这也是一次性的任务。 (但你已经对我投了赞成票。)【参考方案4】:
您可以查看here:
您可以将链接中的命令gsub(/-\(.*\)/,"",$0);
替换为
gsub(/-/,"-0",$0);
并且ls -1
部分将替换为ls -1 clip-????.png
您还需要删除 awk 命令中的搜索部分。
我在下面使用示例文件进行了测试。
@jonathan,我不太明白你说什么。但下面是我做的测试:
> ls -1 clip-????.png
clip-0003.png
clip-1111.png
> ls -1 clip-????.png | nawk 'old=$0;gsub(/-/,"-0",$0);system("mv \""old"\" "$0)'
phoenix.332> ls -1 clip-?????.png
clip-00003.png
clip-01111.png
> ls -1 clip-????.png
ls: No match.
nawk 在 solaris 上。您可以将 awk 用于其他风格的 unix。
【讨论】:
嗯...链接嵌入了一些周围的awk
。就其本身而言,没有标准的gsub
命令,并且符号gsub(...)
将适合shell,因为它会反对它出现的(
(并且将无法找到一个名为/0/,-0,-sh
的命令或附近,如果它不反对括号)。
好的;所以答案不仅仅是gsub(/-/,"-0",$0);
,而是一个嵌入它的awk
脚本。人们不应该去链接来理解你的答案。现在您遇到的问题是它很慢,因为它执行 mv
10,000 次(假设有大约 10,000 个文件要重命名)。但是,这并不能阻止它的工作。以上是关于在 linux 上修复几千个文件名的主要内容,如果未能解决你的问题,请参考以下文章
给定一个包含几千个文件的目录,请输出目录中所有文件名完全相同的列表[重复]
fsck 工具 ——检查 与修复 Linux系统上的文件系统