2008年4月4日

第一次用perl做整個目錄樹的搜尋及修改檔案內容

由於客戶的程式碼某一行少了一個斷行(\n)導致網頁無法正常觀看
,只知道整個網站5萬多支程式裡有問題的檔名為play.html及test.html
,在無法預知有多少支檔案有相同問題狀況下,我決定試著自己寫
程式處理。回想起來我算膽子滿大的,我並不是程式人員,自己學
習寫程式也不過皮毛而已,我只知道要給自己機會練習才能進步,
所以這隻程式包含測試老實說也花了我大約5個鐘頭,以下我就大略
記錄一下當時的想法。

問題需求:
將 D:\htdocs\upload下所有名稱為test.html及play.html的檔案,內
容含有language=JScript.Encode>等字串改為 language=JScript.Encode>\n

處理想法:
1.利用Perl進行目錄樹掃描,遇到檔名為play.html及test.html則進行
讀檔,當有符合時就進行代換的動作。
2.在進行代換前必須備份,且要按照目錄樹來備,若執行有問題就可
以連同目錄蓋回去
3.簡單的log

程式碼:
#!c:\perl\bin\perl

use Cwd;
use strict;

#備份檔存放目錄
my $backupBaseDir = 'c:\backupBase';
#要進行內容檢查的檔案名稱
my @targetFiles = qw/test.html play.html/;

#主程式
scanDirectory('D:\htdocs\upload');


#----------------------------------------------------------------
# 搜尋目錄樹,若找到目錄就遞回呼叫,找到檔案就進行備份及取代
#----------------------------------------------------------------
sub scanDirectory() {
my $workDir = shift;
my $startDir = &cwd;
my @names;

&logme("cd to $workDir");
chdir($workDir)
or die "Unable to enter dir $workDir: $!\n";
opendir(DIR, ".")
or die "Unable to open $workDir: $!\n";
@names = readdir(DIR)
or die "Unable to read $workDir:$!\n";
closedir(DIR);

foreach my $name (@names) {
next if ($name eq '.');
next if ($name eq '..');

if (-d $name) {
&scanDirectory($name);
next;
}

foreach my $target (@targetFiles) {
if ("$name" eq "$target") {
&logme("fix file $name");
&do_backup($name);
&do_replace($name);
}
}
}

chdir($startDir)
or die "Unable to change dir to $startDir:$!\n";
&logme("exit dir to $startDir");
}

#-------------------------------------------------------------
# 備份目錄樹及要更動的檔案
#-------------------------------------------------------------
sub do_backup() {
my $workDir = &cwd();
my $name = shift;
my $backupdir;
my $cmd;

#把&cwd取得的/改成\
$workDir =~ s#/#\\#g;

#重組目錄,加上$backupBaseDir
#eg. c:\321 => $backupBaseDir\321
$workDir =~ /:/;
$backupdir = "$backupBaseDir$'";

#檢查$backupdir是否存在,沒有的話就建立
if (!-d $backupdir) {
$cmd = "mkdir $backupdir";
&logme("mkdir by command $cmd");
system "$cmd";
}

#複製目標檔案至備份目錄
$cmd = "copy $workDir\\$name $backupdir";
print "$cmd\n";
&logme("backup target file by command $cmd");
system "$cmd";

}

#-------------------------------------------------------------
#進行正規表示代換,會建立一個新檔去覆蓋原本的檔案
#-------------------------------------------------------------
sub do_replace() {
my $name = shift;
my $newname = "new_" . $name;
my $cmd;

#開啟需要被更改的檔案
open(FILE, $name)
or die "Unable to open file $name: $!\n";

open(NEWFILE,">$newname")
or die "Unable to open file: $!\n";

&logme("replacing file $name");

while() {
#假如已經有斷行就直接寫到新的檔案
if ($_ =~ /language\s?=\s?\"?JScript.Encode\"?>\n/i) {
print NEWFILE;
} else {
#比對到的話就取代後寫到新檔
$_ =~ s/language\s?=\s?\"?JScript.Encode\"?>/ \
language=\"JScript.Encode\">\n/ig; #這行跟上面那行為同一行
print NEWFILE;
}
}

#關閉開啟的檔案
close(FILE);
close(NEWFILE);

#用新檔覆蓋舊檔
$cmd = "move /y $newname $name";
system("$cmd");
}

#-------------------------------------------------------------
# log函式
#-------------------------------------------------------------
sub logme() {
my $msg = $_[0];
my $logfile = 'c:\fixEncode.log';

open LOGME, ">> $logfile"
or die "Unable to open file $logfile: $!\n";
print LOGME "$msg\n";
close(LOGME);
}

沒有留言:

張貼留言