在 linux 上修复几千个文件名

Posted

技术标签:

【中文标题】在 linux 上修复几千个文件名【英文标题】:Fixing a few thousands filenames on linux 【发布时间】:2013-02-03 18:50:20 【问题描述】:

我使用 ffmpeg 从视频中提取剪辑,遵循此模式 'clip-%4d.png'。

这产生了如下文件:clip-0001.pngclip-0002.png 等等。

然后,我使用 imagemagick "convert" 对这些图片应用了许多过滤器,它运行了几个小时。

我意识到我的列表顺序在clip-9999.png 之后被破坏了,它变成了clip-10000.pngclip-40000.png,成功地破坏了我的剪辑序列。

我想将我的所有剪辑转换为遵循clip-00000.pngclip-00001.pngclip-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 个剪辑要重命名,您可能需要使用 xargsfind 以避免出现“参数列表太长”的问题。

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 上修复几千个文件名的主要内容,如果未能解决你的问题,请参考以下文章

给定一个包含几千个文件的目录,请输出目录中所有文件名完全相同的列表[重复]

Linux中XFS文件系统的备份,恢复,修复

ESX修复Linux虚拟机重启只读模式

fsck 工具 ——检查 与修复 Linux系统上的文件系统

Ext4文件系统fsck后损坏修复方法-linux数据恢复案例

如何修复 CopyFile() 错误 5 - 拒绝访问错误