内容

名称

File::GlobMapper - 扩展文件 Glob 以允许输入和输出文件

概要

use File::GlobMapper qw( globmap );

my $aref = globmap $input => $output
    or die $File::GlobMapper::Error ;

my $gm = File::GlobMapper->new( $input => $output )
    or die $File::GlobMapper::Error ;

描述

此模块需要 Perl5.005 或更高版本。

此模块以现有的 File::Glob 模块为起点,并对其进行扩展,以允许从 File::Glob 匹配的文件中派生新的文件名。

当对具有输入文件名和输出文件名的多个文件执行批处理操作时,这很有用,并且可以从输入文件名派生输出文件。此功能在以下操作中很有用:文件重命名、文件复制和文件压缩。

幕后花絮

为了帮助解释File::GlobMapper的作用,请考虑一下,如果你想将当前目录中所有以.tar.gz结尾的文件重命名为.tgz,你会编写什么代码。假设这些文件位于当前目录中

alpha.tar.gz
beta.tar.gz
gamma.tar.gz

并且需要将它们重命名为以下内容

alpha.tgz
beta.tgz
gamma.tgz

以下是执行重命名的脚本的可能实现(错误情况已被省略)

foreach my $old ( glob "*.tar.gz" )
{
    my $new = $old;
    $new =~ s#(.*)\.tar\.gz$#$1.tgz# ;

    rename $old => $new
        or die "Cannot rename '$old' to '$new': $!\n;
}

请注意,文件通配符模式*.tar.gz用于匹配.tar.gz文件,然后在替换中使用了一个非常相似的正则表达式来创建新的文件名。

鉴于文件通配符只是简化的正则表达式,并且它已经完成了大部分文件名匹配的繁重工作,那么能够使用文件通配符中的模式来驱动新文件名岂不是非常方便吗?

好吧,这就是File::GlobMapper所做的正是这件事。

以下是使用globmap重写的相同代码片段

for my $pair (globmap '<*.tar.gz>' => '<#1.tgz>' )
{
    my ($from, $to) = @$pair;
    rename $from => $to
        or die "Cannot rename '$old' to '$new': $!\n;
}

那么它是如何工作的呢?

在幕后,globmap函数结合了文件通配符来匹配现有文件名,然后进行替换以创建新文件名。

请注意,globmap的两个参数都是用<>分隔的字符串。这样做是为了让它们看起来更像文件通配符 - 这只是语法糖,但在你希望字符串在视觉上具有区分性时会很方便。包围的<>是可选的,因此你无需使用它们 - 事实上,globmap将首先删除这些分隔符(如果存在)。

globmap的第一个参数*.tar.gz是一个输入文件通配符。一旦删除了包围的"< ... >",它将(或多或少)保持不变地传递给File::Glob以执行文件匹配。

接下来,文件通配符*.tar.gz在幕后被转换为完整的 Perl 正则表达式,并额外将每个转换后的通配符元字符序列用括号括起来。

在这种情况下,输入文件通配符*.tar.gz将被转换为以下 Perl 正则表达式

([^/]*)\.tar\.gz

用括号括起来允许输入文件通配符的通配符部分被globmap的第二个参数#1.tgz输出文件通配符)引用。此参数的工作方式与替换命令的替换部分相同。区别在于#1语法用于引用在输入文件通配符中匹配的子模式,而不是$1语法,后者用于 Perl 正则表达式。在这种情况下,#1用于引用由输入文件通配符中的*匹配的文本。这使得在命令行键入globmap的参数时更容易使用此模块。

最后一步涉及将*.tar.gz文件通配符匹配的每个文件名依次通过派生的 Perl 正则表达式,并使用它扩展输出文件通配符。

所有这些的最终结果是一个文件名对列表。默认情况下,这是globmap返回的内容。在本例中,返回的数据结构将如下所示

( ['alpha.tar.gz' => 'alpha.tgz'],
  ['beta.tar.gz'  => 'beta.tgz' ],
  ['gamma.tar.gz' => 'gamma.tgz']
)

每一对都是一个包含两个元素的数组引用 - 即 from 文件名,File::Glob 匹配到的,以及从 from 文件名派生的 to 文件名。

限制

File::GlobMapper 故意保持简单,因此它并不打算解决所有文件名映射操作。在幕后,File::Glob(或对于旧版本的 Perl,File::BSDGlob)用于匹配文件,因此您永远不会拥有完整的 Perl 正则表达式的灵活性。

输入文件 Glob

输入文件 Glob 的语法与 File::Glob 相同,除了以下几点

  1. 没有嵌套的 {}

  2. 空格不分隔文件 glob。

  3. 可以使用括号来捕获输入文件名的部分。

  4. 如果输入 glob 多次匹配同一个文件,则只使用第一个。

语法

~
~user
.

匹配一个字面上的 '.'。等效于 Perl 正则表达式

\.
*

匹配零个或多个字符,除了 '/'。等效于 Perl 正则表达式

[^/]*
?

匹配零个或一个字符,除了 '/'。等效于 Perl 正则表达式

[^/]?
\

反斜杠按惯例用于转义下一个字符。

[]

字符类。

{,}

交替

()

捕获括号,其工作方式与 perl 一样

任何其他字符都按字面意思解释。

输出文件 Glob

输出文件 Glob 是一个普通的字符串,具有 2 个类似 glob 的功能。

第一个是 '*' 元字符。这将被输入文件 glob 匹配的完整文件名替换。所以

*.c *.Z

第二个是

输出文件 Glob 采用

"*"

'*' 字符将被完整的输入文件名替换。

#1

形式为 /#\d/ 的模式将被替换为

返回的数据

示例

重命名脚本

下面是一个简单的“重命名”脚本,它使用 globmap 来确定源文件名和目标文件名。

use File::GlobMapper qw(globmap) ;
use File::Copy;

die "rename: Usage rename 'from' 'to'\n"
    unless @ARGV == 2 ;

my $fromGlob = shift @ARGV;
my $toGlob   = shift @ARGV;

my $pairs = globmap($fromGlob, $toGlob)
    or die $File::GlobMapper::Error;

for my $pair (@$pairs)
{
    my ($from, $to) = @$pair;
    move $from => $to ;
}

以下是一个将所有 c 文件重命名为 cpp 的示例。

$ rename '*.c' '#1.cpp'

一些示例 globmap

下面是一些 globmap 的示例

将所有 .c 文件复制到备份目录

'</my/home/*.c>'    '</my/backup/#1.c>'

如果您想压缩所有

'</my/home/*.[ch]>'    '<*.gz>'

解压缩

'</my/home/*.[ch].gz>'    '</my/home/#1.#2>'

另请参阅

File::Glob

作者

File::GlobMapper 模块由 Paul Marquess 编写,[email protected]

版权和许可

版权所有 (c) 2005 Paul Marquess。保留所有权利。本程序是自由软件;您可以在 Perl 本身的相同条款下重新发布和/或修改它。