2

我正在尝试创建一个将我的所有文件名重命名为 Camel/Capital Case 的过程。我必须到达那里最接近的是:

perl -i.bak -ple 's/\b([a-z])/\u$1/g;' *.txt # or similar .extension.

这似乎创建了一个备份文件(我将在验证这符合我的要求时将其删除);但不是重命名文件,而是重命名文件内的文本。有没有更简单的方法来做到这一点?理论是我有几个不同格式的办公文件,因为我有点保持肛门,并希望它们看起来像这样:

新文档.odt
罗弗勒.ogg
等等等等
鲍勃·卡特.flac
猫狗.avi

perl 可以做到这一点,还是我需要更改为另一种语言/它们的组合?

另外,是否有办法使这个递归,例如 /foo/foo/documents 重命名所有文件,就像 /foo/foo/documents/foo 一样?

4

6 回答 6

9

您需要使用重命名

这是它的签名:


rename OLDNAME,NEWNAME

要使其递归,请将其与File::Find一起使用


use strict;
use warnings;
use File::Basename;
use File::Find;

#default searches just in current directory
my @directories = (".");

find(\&wanted,  @directories);

sub wanted {
  #renaming goes here
}

下面的代码片段将针对找到的所有文件执行内部想要的代码。你必须完成一些代码里面想做你想做的事情。

编辑:我尝试使用 File::Find 来完成这项任务,但我认为你不能轻易实现它。您可以按照以下步骤成功:

  • 如果参数是目录,则大写,获取所有文件

  • 对于每个文件,如果是目录,则以该文件作为参数返回开头

  • 如果文件是普通文件,则大写

Perl 只是在编写这个脚本时妨碍了我。我用 ruby​​ 写了这个脚本:


require "rubygems"
require "ruby-debug"

# camelcase files

class File
    class << self
        alias :old_rename :rename
    end

    def self.rename(arg1,arg2)
        puts "called with #{arg1} and #{arg2}"
        self.old_rename(arg1,arg2)
    end
end

def capitalize_dir_and_get_files(dir)
    if File.directory?(dir)
        path_c          = dir.split(/\//)
        #base           = path_c[0,path_c.size-1].join("/")
        path_c[-1].capitalize!  
        new_dir_name    = path_c.join("/")
        File.rename(dir,new_dir_name)
        files = Dir.entries(new_dir_name) - [".",".."]
        files.map! {|file| File.join(new_dir_name,file)}
        return files 
    end
    return []
end

def camelize(dir)
    files = capitalize_dir_and_get_files(dir)
    files.each do |file|
        if File.directory?(file)
            camelize(file.clone)
        else
            dir_name    = File.dirname(file)
            file_name   = File.basename(file)
            extname     = File.extname(file)
            file_components = file_name.split(/\s+/)
            file_components.map! {|file_component| file_component.capitalize}           
            new_file_name = File.join(dir_name,file_components.join(" "))
            #if extname != ""
            #   new_file_name += extname
            #end
            File.rename(file,new_file_name)
        end
    end
end

camelize(ARGV[0])

我在我的电脑上尝试了这个脚本,它按照你提到的规则将所有目录、子目录和文件大写。我认为这是您想要的行为。很抱歉没有提供 perl 版本。

于 2009-03-24T15:51:42.170 回答
5

大多数系统都有重命名命令....

NAME rename - 重命名多个文件

概要 重命名 [ -v ] [ -n ] [ -f ] perlexpr [ 文件 ]

描述 "rename" 重命名根据指定为第一个参数的规则提供的文件名。perlexpr 参数是一个 Perl 表达式,它被期望为至少一些指定的文件名修改 Perl 中的 $_ 字符串。如果给定的文件名没有被表达式修改,它不会被重命名。如果命令行上没有给出文件名,文件名将通过标准输入读取。

   For example, to rename all files matching "*.bak" to strip the extension, you might say

           rename 's/\.bak$//' *.bak

   To translate uppercase names to lower, you’d use

           rename 'y/A-Z/a-z/' *

选项 -v,--verbose 详细:打印成功重命名的文件名。

   -n, --no-act
           No Action: show what files would have been renamed.

   -f, --force
           Force: overwrite existing files.

作者拉里·沃尔

诊断 如果你给出一个无效的 Perl 表达式,你会得到一个语法错误。

于 2009-03-25T09:49:38.537 回答
3

由于 Perl 在多个平台上运行良好,让我警告您 FAT(和 FAT32 等)文件系统将忽略仅更改文件名大小写的重命名。这在 Windows 和 Linux 下是正确的,对于支持 FAT 文件系统的其他平台可能也是如此。

因此,除了Geo's answer之外,请注意您可能必须实际更改文件名(例如,通过在末尾添加一个字符),然后将其更改回您想要的名称,并使用正确的大小写。

如果您只重命名 NTFS 文件系统或 ext2/3/4 文件系统(或其他 UNIX/Linux 文件系统)上的文件,那么您可能不需要担心这一点。我不知道 Mac OSX 文件系统是如何工作的,但由于它基于 BSD,我认为它只允许您通过更改名称的大小写来重命名文件。

于 2009-03-24T16:00:53.660 回答
1

另一个:

find . -type f -exec perl -e'
  map {
        ( $p, $n, $s ) = m|(.*/)([^/]*)(\.[^.]*)$|;
        $n =~ s/(\w+)/ucfirst($1)/ge;
        rename $_, $p . $n . $s;
      } @ARGV
  ' {} +
于 2009-03-25T16:21:01.793 回答
1

我只是使用 find 命令递归子目录和 mv 进行重命名,但仍然利用 Perl 来获得正确的重命名。

find /foo/foo/documents -type f \
     -execdir bash -c 'mv "$0" \
                          "$(echo "$0" \
                              | perl -pe "s/\b([[:lower:]])/\u\$1/g; \
                                          s/\.(\w+)$/.\l\$1/;")"' \
              {} \;

神秘,但它有效。

于 2009-03-24T20:30:07.023 回答
0

请记住,在记住大小写的文件系统 (FAT/NTFS) 上,您需要先将文件重命名为其他名称,然后再更改大小写。从“etc.etc”直接重命名为“Etc.Etc”将失败或被忽略,因此您需要进行两次重命名:“etc.etc”为“etc.etc~”,然后为“etc.etc~”例如,“Etc.Etc”。

于 2009-03-25T16:42:24.003 回答