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 正規表示式的彈性。
輸入 FileGlob 的語法與 File::Glob
相同,但下列例外
沒有巢狀 {}
空白不區分檔案 Glob。
括號的使用可於擷取輸入檔案名稱的部分。
如果輸入 Glob 多次相符同一個檔案,只會使用第一個。
語法
相符一個字面上的「.」。等同於 Perl 正規表示式
\.
相符零個或多個字元,除了「/」。等同於 Perl 正規表示式
[^/]*
相符零個或一個字元,除了「/」。等同於 Perl 正規表示式
[^/]?
反斜線用於跳脫下一個字元,如同平常一樣。
字元類別。
交替
擷取括號,作用就像 perl
任何其他字元都照字面意思取用。
輸出檔案 Glob 是個一般字串,有 2 個類似 Glob 的功能。
第一個是「*」元字元。這將會被輸入檔案 Glob 相符的完整檔案名稱取代。因此
*.c *.Z
第二個是
輸出 FileGlobs 取用
以下是一個簡單的「重新命名」指令碼,它使用 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 的範例
將所有 .c 檔案複製到備份目錄中
'</my/home/*.c>' '</my/backup/#1.c>'
如果您想要壓縮所有
'</my/home/*.[ch]>' '<*.gz>'
要解壓縮
'</my/home/*.[ch].gz>' '</my/home/#1.#2>'
File::GlobMapper 模組是由 Paul Marquess 編寫的,pmqs@cpan.org。
版權所有 (c) 2005 Paul Marquess。保留所有權利。此程式是免費軟體;您可以在與 Perl 相同的條款下重新散布或修改它。