#!/usr/bin/perl $CPU_start = (times)[0] ; ############################################## # スクリプトを置いたディレクトリの差分ファイルを作成する # ver.0.11b 2006/9/28 MacPerl版 # ・原型はpullout_twoで、ドロップではなく設置位置で抜き出し元ディレクトリを判断するにうに変更し、抜き出した後にFTPで特定のサーバにアップする、機能を追加した。 ############################################## ############################################## # 変数の設定 ############################################## $lasttimefile = '_最終チェック日'; # 前回のmake時間とファイルデータを覚えておくファイル $omittxt = '_'; # この文字列で始まるフォルダ/ファイルは無視する # MacPerlの場合:デスクトップの出力用フォルダ名。空ならデスクトップに書き出される。 #  MacPerlの例:「共有:」とすると、デスクトップにある「共有」フォルダ内に書き出される。最期の「:」を忘れずに # UNIX perlの場合:出力用ディレクトリの絶対パス。 #  UNIX perlの例:「/Users/name/Desktop/backup/」最期の「/」を忘れずに $outdir = "共有:"; #### FTP関係の設定 $afterftp = '0'; # 抜き出した後、FTPでアップロードするなら1、しないなら0か空。 # FTPアップロードするなら以下も設定が必要。しなければままでOK。 $hostname = "abcdefg.ne.jp";# 接続先 $loginname = "yourname";# ID ログイン名 $loginpasswd = "loginpasswd";# ログインパスワード $basedir ="/html/dirname/" ; # アップ先ディレクトリをFTPのフルパスで $pasv = "1"; # モード指定。空ならアクティブモード、1ならパッシブモード ############################################## # メインルーチン ############################################## $debug = '0'; # 0ならノーマル、1でデバッグ $folplus = '_dif'; # フォルダ名の後ろに付ける名前 # Classic MacかOS Xか自動判定してモジュールの宣言=============== $cr = "\x0D"; $lf = "\x0A"; if ("\n" eq $cr){ # MacPerl $pc = '1'; use File::Copy; # ファイルコピーに使用 }else { # OS X $pc = '0'; } if($afterftp == '1'){use Net::FTP;}# FTPするなら use Time::Local; # 年月日>秒数変換のため use Cwd; # 自分の位置を知るため use File::Path; # フォルダ削除のため/ rmtree # 変数を整える================================= $num = 0; # コピーしたファイル数 $nowsec = time(); # 現在の秒数 $copymode = ''; # コピーモード $targetdir = getcwd; # スクリプトのあるディレクトリ if ($pc == '1'){ # AppleScriptを使ってデスクトップを取得 $desktop = &MacPerl'DoAppleScript('set aaa to (the path to the desktop folder) as text'); $desktop =~ s/"//g; # 余分な"がつくので削除 $desktop = $desktop.$outdir ; # フオルダ名を追加 @aaa = split( /:/, $targetdir ); # :で分解して } else { $desktop = $outdir; @aaa = split( /\//, $targetdir ); # /で分解して } # 処理対象フォルダ名 $dropfol = pop(@aaa); # 最期を取り出す if ($pc == '1'){ $copyfol = $dropfol.$folplus.":" ; print "差分取りだし処理開始\n"; } else { $copyfol = $dropfol.$folplus."/" ; } if ($debug == 1){ print "dropitem $targetdir\n"; print "desctop $desktop\n"; print "dropfol $dropfol\n"; print "copyfol $copyfol\n"; } # 処理開始================================= $lasttime = &getltime($targetdir); # 前回の処理時間(秒) if ($lasttime eq ""){ # ファイルがなかったら $copymode = '1'; # コピーモード1 } &hantei($targetdir); &writetime($targetdir); # 今回の処理時間を保存 $CPU_end = (times)[0]; $cputime = sprintf("%.5f", $CPU_end-$CPU_start); if ($copymode == 1) { print "初回なので「$lasttimefile」を作成しました。\n消費時間: $cputime CPU秒\n"; } else { if($afterftp == '1'){ # FTPするなら if($num > 0){ # コピーしていたら $seikou = &ftpupload("$desktop$copyfol"); # FTP処理 if ($seikou == '1'){ # エラーがあった print "FTPアップに失敗しました。\n"; } else { # 成功なら作成したディレクトリを削除 $copyfol =~ s/\/$//; # 最期の/を削除 $copyfol =~ s/:$//; # 最期の:を削除 rmtree "$desktop$copyfol" ; # File::Pathで一気に削除 } } else { print "コピーファイルがないのでFTPはスキップします。\n"; } } print "\nコピーファイル数:$num\n消費時間: $cputime CPU秒\n"; } print "\a"; # beep exit; ############################################## #  以下、サブルーチン ############################################## # ================================================================== # ファイルかフォルダかを判定してそれぞれの処理に飛ばす。 # ================================================================== sub hantei { my $thisitem = $_[0]; if($pc == '1'){# MacPerl $thisitem =~ s/::/:/g ; # ::を:に } else { $thisitem =~ s/\/\//\//g ; # //を/に } if (-d $thisitem){ # ディレクトリの場合 &forDir($thisitem) ; # ディレクトリ処理ルーチンに飛ばす } else { if (-f $thisitem){ # ファイルの場合 if ($thisitem !~ m/^\./){ # .で始まっていたら無視 &forFile($thisitem) ; # ファイル処理ルーチンに飛ばす } } else { # ここに来たら変。エラー処理を書く print "判定エラー $thisitem\n"; @stat = stat $thisitem; foreach $thisstat(@stat){ print " > $thisstat\n"; } } } } # ================================================================== # ディレクトリ用の処理を書く # ================================================================== sub forDir { my $dirname = $_[0]; my (@filelist, $thislist); if($debug == 1){print "フォルダだ $dirname\n"; }# my $thisdir = &getlastname($dirname); # ディレクトリ名を取り出して if($thisdir !~ /^$omittxt/){ # オミットも時で始まっていなければ処理する # このフォルダの下のリストを取得する。 opendir (DIR , $dirname) || die "Cannot open dir $dirname" ; @filelist = readdir(DIR); closedir(DIR) ; # そのリストを&hantei(リスト);に投げ戻す。再起処理ですね。 foreach $thislist (@filelist) { if ($thislist =~ m/^\./){ next;} # .で始まっていたら無視 if ($pc eq "1"){# mac $foldirlist = "$dirname:$thislist"; } else { # unix $foldirlist = "$dirname/$thislist"; } &hantei("$foldirlist"); } } } # ================================================================== # ファイル用の処理を書く # ================================================================== sub forFile{ my($content); my $thisfile = $_[0]; my $flg =''; # フラグの初期化 if($thisfile !~ /$lasttimefile$/){ # 記録ファイルでなければ my $thisname = &getlastname($thisfile); # ファイル名を取り出して if($thisname !~ /^$omittxt/){ # オミット文字で始まっていなければ処理する $modtime = (stat($thisfile))[9] ; # ファイルの更新日時(秒)取得 if( $lasttime < $modtime){ # 前回の処理より新しければ処理する $flg = '1'; # フラグを立てる } chomp $thisfile; # 余分な改行に備える if( exists $filedb{$thisfile}){ # 前回のデータにある $filedb_new{$thisfile} = $modtime; # 新しいデータに更新 } else { # 前回のデータにない $flg = '1'; # フラグを立てる $filedb_new{$thisfile} = $modtime; # データを追加 if($copymode == 1){ # 初回だったら $flg = ''; # フラグを降ろす。つまりデータの取得だけ } } if( $flg == 1){ # フラグが立っていれば処理する $num++; # カウントアップ $newdir = $thisfile; $newdir =~ s/$targetdir/$copyfol/g ; # 保存場所をすり替え &dircheck("$newdir"); # ディレクトリのチェック。必要なら作成 if($debug == 1){ print " ファイルだ $thisfile\n"; } else { if($pc == '1'){ print "$num : $thisfile\n"; } } $newfile = $thisfile; $newfile =~ s/$targetdir/$copyfol/g ; # 保存場所をすり替え if($pc == '1'){ copy("$thisfile", "$desktop$newfile"); } else { # cpやmvがリソースフォークコピーをサポートするのは10.4からなので、ここではシェルにコピーしてもらう。 $cmd = "ditto -rsrcFork \"$thisfile\" \"$desktop$newfile\""; readpipe $cmd ; # コマンドを投げる } } } } } # ============================================== # UNIXのパスをMacのパスに変換 for MacPerl # if ($pc eq "1"){$aaa = &mac_dir(ディレクトリ); }のように呼び出す # パスだけに使う方が無難。URLには使わないこと。 sub mac_dir { my $mydir = $_[0]; $mydir =~ s/^\.\//:/g ; # 行頭の./を:に $mydir =~ s/^\.\.\//::/ ; # 行頭の../を::に $mydir =~ s/\.\.\//:/g ; # すべての../を:に $mydir =~ s/\//:/g ; # /をすべて:に return $mydir; } # ============================================== # 受けとったファイルパスからディレクトリ名だけ取り出して、 # それが存在するかチェックし、存在しなければ作成する。 # &dircheck("パス"); のように呼び出す。 sub dircheck{ my $checkdir = $_[0]; # ファイル名 # ディレクトリの取得 if($pc == '1'){ # MACなら @dirlist = split( /:/, $checkdir ); # :で分解 pop @dirlist; # 最期(ファイル名)を削除 $checkdir = join(':',@dirlist);# :でつなぐ } else { @dirlist = split( /\//, $checkdir ); # /で分解 pop @dirlist; # 最期(ファイル名)を削除 $checkdir = join('/',@dirlist);# /でつなぐ } $checkdir =~ s/$targetdir/$copyfol/g ; # 保存場所をすり替え if($degug == 1){print "checkdir : $checkdir\n";} chdir $desktop; # デスクトップに移動して # homeにそのディレクトリがあるかチェックして、なければ作成 if (-e $checkdir){ # ディレクトリがあるか # あった if($debug == 1){print "$checkdir --ok\n";} } else { &makedir("$checkdir"); # ディレクトリを作成して if($debug == 1){print "$checkdir --make\n";} } chdir $basedir; # 元のディレクトリへ戻る } # ================================== # 深い階層まで一気にディレクトリを作成する # &makedir("xxx/yyy/zzz"); のように呼び出す # MacPerlではuse File::Pathがうまく動作しないので作成した sub makedir{ my $dir = $_[0]; my (@dirlist,$thisdir); if($pc eq "1"){ # MACなら @dirlist = split( /:/, $dir ); # :で分解 } else { @dirlist = split( /\//, $dir ); # /で分解 } foreach $thisdir ( @dirlist ) { if($thisdir eq ""){next;} # 空なら無視 if ($thislist =~ m/^\./){next;} # .で始まっていたら無視 mkdir("$thisdir"); chdir("$thisdir"); } chdir $basedir ; # 元のディレクトリに戻る } # ============================================== #特定の部分を取り出すルーチン # $aaa = &toridasi(対象文字列,開始文字列,終わり文字列);のように呼び出す sub toridasi{ my $mojiretu = $_[0]; my $begin = @_[1]; my $end = @_[2]; $mojiretu =~ m/$begin(.*?)$end/is; my $toridasi= $1; return $toridasi; } # =================================== # ファイルを読み込んで返すルーチン その2 # ファイルが存在するかチェックしてから読み込む。存在しない場合は別の内容を返す。 # $aaa = &read_file(ファイル名); のように呼び出す。 sub read_file { my $socefile = $_[0]; # ファイル名の受け取り if ($pc eq "1"){$socefile = &mac_dir($socefile); } my $allfile = ""; # 初期化 if (-e $socefile){ # ファイルがあったら # ファイルのオープン open (RSS,"<$socefile")|| die "ファイル「$socefile」が開けません"; #ファイルの読み込み while ($_ = ){ $allfile .= $_; # 最後まで読む } #ファイルのクローズ close (RSS) ; } else { # ファイルがなければ $allfile = "" ; # 必要に応じてエラーなどを入れる } return $allfile ; # 送り返す } # =================================== # ファイルの書き出し # &write_file(ファイル名,内容,モード); のように呼び出す。 # モードは0で上書き、1で追記 sub write_file { my $filename = $_[0]; my $content = @_[1]; my $mode = @_[2]; # 書き込みファイルのオープン if ($mode eq "0") { # 上書き open (FILE,">$filename")|| die "ファイル「$filename」に出力できません"; } else { if ($mode eq "1") { # 追記 open (FILE,">>$filename")|| die "ファイル「$filename」に出力できません"; } } print (FILE "$content") ; # ファイルに出力 #ファイルのクローズ close (FILE) ; } # =================================== # 秒数を日時に変換 # $aaa = &change_time(秒数); のように呼び出す。 # 秒数を time にすると現在時刻を返す sub change_time { my $thistime = $_[0]; local($lsec, $lmin, $lhour, $lmday, $lmon, $lyear,$lthis_day); ($lsec, $lmin, $lhour, $lmday, $lmon, $lyear) = localtime($thistime); $lthis_day = sprintf("%04d\/%02d\/%02d\ %02d\:%02d:%02d", $lyear+1900,$lmon+1,$lmday,$lhour,$lmin,$lsec); # 2002/08/06 14:05:30形式 return $lthis_day; } # ========================== # パスからファイル/ディレクトリ名を取り出す # $aaa = &getlastname(パス); で呼び出す sub getlastname { my $thispath = $_[0]; my(@pathlist,$thisname); if($pc == 1){ # MacPerl @pathlist = split( /:/, $thispath ); # :で分解 } else { @pathlist = split( /\//, $thispath ); # /で分解 } $thisname = pop(@pathlist); return $thisname; } # =================================== # 前回の処理時間を読み込んで返す # $aaa = &getltime(ディレクトリ名); で呼び出す。 sub getltime{ my $socefile = $_[0]; # ファイル名の受け取り my($aaa,$lasttime); $socefile .= $lasttimefile; if ($pc eq "1"){$socefile = &mac_dir($socefile); } if (-e "$socefile"){ # 前回の記録ファイルがあったら # ファイルのオープン open (DBFILE,"<$socefile")|| die "ファイル「$socefile」が開けません"; #ファイルの読み込み while ($thisline = ){ ($key, $val) = split(/\t/,$thisline,2); # タブで分割 if($val == ""){ # 2つ目がなければ前回の時間 if($key ne ""){ # 空でなければ print "前回の時間:$key\n"; $key =~ m/(\d+)\/(\d+)\/(\d+)\s(\d+)\:(\d+)\:(\d+)/s; # 分解 $year = $1; $month = $2; $day = $3; $hour = $4; $min = $5; $sec = $6; $month =~ s/^0//g; # 頭の0を削除 $day =~ s/^0//g; # 頭の0を削除 $hour =~ s/^0//g; # 頭の0を削除 $min =~ s/^0//g; # 頭の0を削除 $sec =~ s/^0//g; # 頭の0を削除 $lasttime = timelocal($sec,$min,$hour,$day,$month-1,$year);# 年月日>秒数 } } else { # ファイルのデータ $filedb{$key} = $val; # 変数に格納。$filedb{ファイル名}で更新時間を取り出せる } } #ファイルのクローズ close (DBFILE) ; } else { $lasttime = ''; } return $lasttime; } # 今回の時間を記録しておく================================ # &writetime(ディレクトリ); で呼び出す。 sub writetime{ my $socefile = $_[0]; # ファイル名の受け取り my($nowtime); $socefile .= $lasttimefile; if ($pc eq "1"){$socefile = &mac_dir($socefile); } $nowtime = &change_time(time); # 現在時刻 # 書き込みファイルのオープン open (FILE,">$socefile")|| die "ファイル「$socefile」に出力できません"; print (FILE $nowtime."\n") ; # 最初に時間 while (($key,$value ) = each %filedb_new){ print (FILE $key."\t".$value."\n") ; # データの書き込み } #ファイルのクローズ close (FILE) ; } # FTPでアップロードする================================ # evalでエラートラップした。dieすると$@にエラー内容が入る。 # $aaa = &ftpupload(アップするディレクトリパス); で呼び出し。 # 返り値が空なら成功、1なら失敗。 sub ftpupload { my $updirname = $_[0]; # アップするディレクトリの受けとり my $flg ='' ; # 成功したかどうかのフラグ print "\nFTPアップロード開始。 $updirname ==============\n"; eval { $ftp = Net::FTP->new($hostname, Passive => $pasv, Debug => 1); # Net::FTP接続。 $ftp->login($loginname, $loginpasswd); # Net::FTPログイン。 # Net::FTP転送モードをバイナリに設定 $ftp->binary();# ascii/binary/etc mode $ftp->cwd($basedir) || die("ディレクトリ移動失敗"); # 準備完了 # このフォルダの下のリストを取得する。 opendir (DIR , $updirname) || die "Cannot open dir $dirname" ; my @filelist = readdir(DIR); closedir(DIR) ; # そのリストを&hanteiFtp(リスト);に投げる foreach my $thislist (@filelist) { if ($thislist =~ m/^\./){ next;}# .で始まっていたら無視 my $foldirlist = "$updirname:$thislist"; if($pc == '1'){# MacPerl $foldirlist =~ s/::/:/g ; # ::を:に } else { $foldirlist =~ s/\/\//\//g ; # //を/に } &hanteiFtp("$foldirlist"); } $ftp->quit; # Net::FTP終了 }; # evalなので}の後ろに;が必要 if($@){ # エラーで止まったら $ftp->quit; # Net::FTP終了 $flg = "1"; # 失敗フラグ print "FTP ERROR !!!! $@\n"; # エラーを表示。 } else { print "\nFTP終了\n"; } return $flg ; # フラグを返す } # ================================================================== # 判定/FTP sub hanteiFtp { my $thisitem = $_[0]; if($pc == '1'){# MacPerl $thisitem =~ s/::/:/g ; # ::を:に } else { $thisitem =~ s/\/\//\//g ; # //を/に } if (-d $thisitem){ # ディレクトリの場合 &forFtpDir($thisitem) ; # ディレクトリ処理ルーチンに飛ばす } else { if (-f $thisitem){ # ファイルの場合 &forFtpFile($thisitem) ; # ファイル処理ルーチンに飛ばす } else { # ここに来たら変。エラー処理を書く print "判定エラー $thisitem\n"; } } } # ================================================================== # ディレクトリ用の処理を書く/FTP sub forFtpDir { my $dirname = $_[0]; my (@filelist, $thislist); if($debug == '1'){print "\nフォルダだ $dirname\n"; } # $desktop$copyfolで分解すればその下のディレクトリが取り出せるはずだ。 @dirlist = split( /$desktop$copyfol/, $dirname ); # $desktop$copyfolで分解 my $thisdirname = pop @dirlist; # 最期(起点以後のパス名)を取り出す $thisdirname =~ s/:/\//g; # :を/に変換 eval { # FTP先でそのディレクトリに降りてみる $ftp->cwd("$basedir$thisdirname") || die("ディレクトリ移動失敗"); }; if($@){ # 降りられなかったら # ディレクトリがないので作成する $ftp->mkdir("$basedir$thisdirname",true) || die("ディレクトリ作成失敗"); $ftp->cwd("$basedir$thisdirname") || die("ディレクトリ移動失敗"); # そこへ移動 } # このフォルダの下のリストを取得する。 opendir (DIR , $dirname) || die "Cannot open dir $dirname" ; @filelist = readdir(DIR); closedir(DIR) ; # そのリストを&hanteiFtp(リスト);に投げ戻す。再起処理ですね。 foreach $thislist (@filelist) { if ($thislist =~ m/^\./){ next;}# .で始まっていたら無視 my $foldirlist = "$dirname:$thislist"; if($pc == '1'){# MacPerl $foldirlist =~ s/::/:/g ; # ::を:に } else { $foldirlist =~ s/\/\//\//g ; # //を/に } &hanteiFtp("$foldirlist"); } } # ================================================================== # ファイル用の処理を書く/FTP sub forFtpFile{ my $thisfile = $_[0]; # Net::FTPファイルのアップロード。 $ftp->put($thisfile) || die("アップロード失敗"); }