內容

名稱

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;
}

請注意,檔案 glob 樣式 *.tar.gz 用於比對 .tar.gz 檔案,然後在替換中使用相當類似的正規表示法,以建立新的檔案名稱。

由於檔案 glob 僅為精簡的正規表示法,且已在檔案名稱的樣式比對中完成許多繁瑣的工作,因此使用 fileglob 中的樣式來驅動新的檔案名稱是否會很方便?

嗯,這正是 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 函式會結合檔案 glob 來比對現有的檔案名稱,然後使用替換來建立新的檔案名稱。

請注意,傳遞給 globmap 的兩個參數都是以 <> 分隔的字串。這樣做是為了讓它們看起來更像是檔案 glob - 這只是語法糖,但當您希望字串在視覺上具有區別性時,它會很方便。封閉的 <> 是可選的,因此您不必使用它們 - 事實上,如果 globmap 存在,第一件事就是移除這些分隔符號。

傳遞給 globmap 的第一個參數 *.tar.gz輸入檔案 Glob。移除封閉的 "< ... >" 後,會將其(或多或少)不變地傳遞給 File::Glob 以執行檔案比對。

接下來,檔案 glob *.tar.gz 在幕後轉換為完整的 Perl 正規表示法,並額外將每個轉換後的萬用字元元字元序列用括號括起來。

在這種情況下,輸入檔案 glob *.tar.gz 將轉換為此 Perl 正規表示法

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

以括號包覆可讓第二個參數 globmap 參照輸入檔案 Glob 的萬用字元部分,#1.tgz,即為 輸出檔案 Glob。此參數的作用就像替換指令的替換部分。不同的是,#1 語法用於參照輸入檔案 Glob 中相符的子模式,而不是 Perl 正規表示式中使用的 $1 語法。在此情況下,#1 用於參照輸入檔案 Glob 中 * 相符的文字。這讓使用者在命令列中輸入 globmap 參數時更為便利。

最後一個步驟包括依序傳遞 *.tar.gz 檔案 Glob 相符的每個檔案名稱,並使用衍生的 Perl 正規表示式,並使用它擴充輸出檔案 Glob。

所有這些的最終結果是檔案名稱對清單。預設情況下,這是 globmap 回傳的內容。在此範例中,回傳的資料結構看起來會像這樣

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

每個對應都是包含兩個元素的陣列參考,也就是 來自 檔案名稱,File::Glob 已相符,以及從 來自 檔案名稱衍生的 前往 檔案名稱。

限制

File::GlobMapper 故意保持簡單,因此它並非用於解決所有檔案名稱對應操作。在底層,File::Glob(或對於較舊版本的 Perl,File::BSDGlob)用於對應檔案,因此您永遠無法擁有完整 Perl 正規表示式的彈性。

輸入檔案 Glob

輸入 FileGlob 的語法與 File::Glob 相同,但下列例外

  1. 沒有巢狀 {}

  2. 空白不區分檔案 Glob。

  3. 括號的使用可於擷取輸入檔案名稱的部分。

  4. 如果輸入 Glob 多次相符同一個檔案,只會使用第一個。

語法

~
~user
.

相符一個字面上的「.」。等同於 Perl 正規表示式

\.
*

相符零個或多個字元,除了「/」。等同於 Perl 正規表示式

[^/]*
?

相符零個或一個字元,除了「/」。等同於 Perl 正規表示式

[^/]?
\

反斜線用於跳脫下一個字元,如同平常一樣。

[]

字元類別。

{,}

交替

()

擷取括號,作用就像 perl

任何其他字元都照字面意思取用。

輸出檔案 Glob

輸出檔案 Glob 是個一般字串,有 2 個類似 Glob 的功能。

第一個是「*」元字元。這將會被輸入檔案 Glob 相符的完整檔案名稱取代。因此

*.c *.Z

第二個是

輸出 FileGlobs 取用

"*"

「*」字元將會被完整的輸入檔名取代。

#1

形式為 /#\d/ 的模式將會被

傳回資料

範例

A 重新命名指令碼

以下是一個簡單的「重新命名」指令碼,它使用 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'

幾個範例 globmaps

以下是一些 globmaps 的範例

將所有 .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 編寫的,pmqs@cpan.org

版權和授權

版權所有 (c) 2005 Paul Marquess。保留所有權利。此程式是免費軟體;您可以在與 Perl 相同的條款下重新散布或修改它。