NASで自作スクリプト!『履歴バックアップ』や『このファイルは7日で消える…』を作ってみた
~NASでスクリプト言語が動いたらこんなに便利![後編]~
2017年4月28日 06:02
前回、ASUSTORのNASボックス“AS6204T”にPerlを導入する手順と、その動作確認方法までを紹介した。NASボックスは、内部でLinuxが動いているため、こうしたことも可能となる。
そして、スクリプト言語が使えれば、NASの“ちょっとかゆいところに手がとどく”ようになる。今回は、NAS上のPerlを活用すべく、簡単なスクリプトを5つ作ってみた。
具体的には以下の通りだが、純粋にサンプル的なものだけでなく、『履歴バックアップ』や 『7日で消えるファイル』『写真整理』など、アイデア的には「アリ」なものが作れたと思う。エラー処理や実行効率などは改善の余地があるが、NASの深い活用の一助になれば幸いだ。
なお、ASUSTORのNASはPerlのほかに、RubyやPythonも利用可能。それらの言語が得意な方は言語を変えてチャレンジしてみるのもいいだろう。
【作ってみたサンプルスクリプト】
●テキスト処理
NASに置いたファイルをテキスト処理。ファイル入出力と正規表現で
●Webページの取得
HTTP:TinyでWebページを取得する
●写真整理
NAS上で常時実行、特定フォルダに置いたファイルを自動でフォルダ分け
●履歴バックアップ
NAS上で常時実行、特定フォルダのファイルを履歴バックアップ
●7日で消えるファイル
NAS上で常時実行、7日更新されないファイルを自動で削除
まずは簡単なファイル入出力と正規表現で
Perlと言えば強力な正規表現。そこで最初にテキストデータを整形するスクリプトを組んでみた。
スクリプトと同じフォルダーにテキストファイルを置き、SSHクライアントでPerlを実行する、というシンプルなサンプルだ。
ちなみにこのスクリプト、実は筆者の仕事でも使っているもの。筆者は普段、自作PCのベンチマーク記事などを書いているのだが、ベンチマーク結果ファイルからグラフを作成するには、テキストデータをちまちまとExcelのセルへコピペしなくてはならない。しかし、手入力は間違いのもと……というわけで、スクリプトの登場というわけだ。
ターゲットとしたのは窓の杜でも収録している「CrystalDiskMark」の結果ファイル。テキスト形式なので扱いも簡単だ。ただし一つズルをしている。「CrystalDiskMark」の[ファイル]メニューから保存をして作成されるのはUTF-16形式のファイルで、これを扱うのはメンドクサイ。そこで、[ファイル]メニューから[コピー]を選んでからメモ帳に貼り付けたファイルを対象とすることにした。Perlでも作り込めば文字コードの異なるファイルを扱えるようになるので、時間のある方は試していただきたい。
ではサンプルコード。
cdmfix.pl
#!/usr/bin/perl
use utf8;
my $file = "cdm.txt"; #入力ファイル名
my $fileout = "cmdfix.txt"; #出力ファイル名
open(DATAFILE, "<:utf8",$file) or die("Error:$!");
open(DATAFILEOUT, ">> $fileout") or die("error :$!");
while (my $line = ){
if($line =~ /T\=.1/){
$line =~ s/\s.*?://;
$line =~ s/[MB\/s|IOPS|\s|\]]//g;
if($line =~ /\[/){
$line =~ s/\[/\n/;
}
print "$line\n";
print DATAFILEOUT "$line\n";
}
}
close(DATAFILE);
close(DATAFILEOUT);
このスクリプトと同じフォルダーに“cdm.txt”として保存した「CrystalDiskMark」の結果ファイルを置けば、整形をした後“cmdfix.txt”として出力する。「Excel」にコピペすることが前提なので、データの値と順番が合っていれば結果ファイルは数字の列だけで構わないということで、文字や記号はバッサリ切り捨てている。
実行するとこのような感じ。
そして“cdm.txt”が
cdm.txt
-----------------------------------------------------------------------
CrystalDiskMark 5.2.1 x64 (C) 2007-2017 hiyohiyo
Crystal Dew World : http://crystalmark.info/
-----------------------------------------------------------------------
* MB/s = 1,000,000 bytes/s [SATA/600 = 600,000,000 bytes/s]
* KB = 1000 bytes, KiB = 1024 bytes
Sequential Read (Q= 32,T= 1) : 558.134 MB/s
Sequential Write (Q= 32,T= 1) : 450.675 MB/s
Random Read 4KiB (Q= 32,T= 1) : 231.284 MB/s [ 56465.8 IOPS]
Random Write 4KiB (Q= 32,T= 1) : 192.028 MB/s [ 46881.8 IOPS]
Sequential Read (T= 1) : 508.520 MB/s
Sequential Write (T= 1) : 445.858 MB/s
Random Read 4KiB (Q= 1,T= 1) : 16.181 MB/s [ 3950.4 IOPS]
Random Write 4KiB (Q= 1,T= 1) : 36.974 MB/s [ 9026.9 IOPS]
Test : 1024 MiB [D: 99.2% (924.3/931.4 GiB)] (x5) [Interval=5 sec]
Date : 2017/03/31 16:57:46
OS : Windows 10 Professional [10.0 Build 14393] (x64)
“cdmfix.txt”に整形される
cdmfix.txt
558.134
450.675
231.284
56465.8
192.028
46881.8
508.520
445.858
16.181
3950.4
36.974
9026.9
HTTP:TinyでWebページを取得する
次は、ネットワークを使ったサンプル、ということで、HTTP::Tinyモジュールを使ったサンプルだ。
HTTP::Tinyモジュールを使い、特定のURLにアクセスしてレスポンスを確認、取得した内容をテキストファイルとして出力している。本当に「取得するだけ」なので、活用法は各自検討してほしい。
httptiny.pl
#!/usr/bin/perl
use strict;
use warnings;
use HTTP::Tiny;
my $url = "http://www.watch.impress.co.jp/";
my $fileout = "data.txt";
my $ua = HTTP::Tiny->new(
agent => 'sample ua',
);
my $res = $ua->get($url);
die "Can't download $url\n" unless $res->{success};
open(FILEOUT, ">> $fileout") or die("error :$!");
print FILEOUT $res->{content};
close(FILEOUT);
my $result = $res->{reason};
print "$result : OK\n";
写真を日付でフォルダー管理する
次は、特定フォルダーを監視し、指定の拡張子のファイルが追加された場合、それをファイルの最終更新日によってフォルダー分けしよう、といった内容だ。
フォルダー監視にはループを用いた。今回は、万一を考えてループ回数を決め打ちしたが、動作が確認できるなら無限ループにしてもいいだろう。バックグラウンドプロセスとして動作させれば、SSHクライアントを開き続ける必要もなくなる。
なお、無理やりスクリプトを止めたい場合は、SSHクライアントからkillコマンドを使って行う。
photoorganizing.pl
#!/usr/bin/perl
use strict;
use warnings;
use Time::Piece;
use File::Copy;
my $maxloop = 24; #ループ回数上限
my $sleeptime = 3600; #スリープ時間(秒)
my $photostock = "./PhotoStock/"; #監視対象のフォルダ
chdir($photostock);
my @file ="";
my $i=1;
while($i<=$maxloop){
print "LOOP\=$i\n";
@file = glob "*.JPG *.jpg";
foreach(@file){
my ($sec, $min, $hour, $day, $mon, $year) = localtime((stat($_))[9]);
$year = $year + 1900;
$mon = $mon + 1;
my $timestmp = sprintf("%04d-%02d-%02d",$year,$mon,$day);
if(!-d "./".$timestmp){
mkdir "./".$timestmp;
}
print "\t$_ \-\> \.\/$timestmp\/$_\n";
move $_, "./".$timestmp."/".$_;
}
sleep ($sleeptime);
$i++;
}
まず、スクリプト実行前のファイル一覧がこちらだ。
それではスクリプトを実行してみる。
そして、スクリプトで処理されると自動的に日付フォルダーが作成され、ファイルが移動する。
“PhotoStock”フォルダーに写真を放り込めば、(スクリプトがループしている間は)自動的に日付によるフォルダーで整理されるようになった。
ただ、実際に使ってみると日付で管理することが便利かというとそうでもない。1週間のイベント取材ともなると日単位ではなく月単位や週単位あたりが適当だろうか。そうした各個人の調節も、自作スクリプトなら実現できる。
ループを使いこなして『履歴バックアップ』
ここからはもう1段、実用的なスクリプトを考えた。前回使ったループ処理を活用し、今度は履歴バックアップをやってみたい。
処理の流れとしては、ループのなかで監視フォルダーのファイルの更新日時をチェック、バックアップ先のフォルダーに“更新日時+そのファイル名”のファイルがあるかないかを判断、なければ“更新日時+そのファイル名”としてバックアップするというものだ。
また、せっかくなので、NASの機能との連動も考えてみた。具体的には『Google Driveの内容をNAS上で履歴バックアップさせてみる』というもの。実際は、『NASのGoogle Drive連動フォルダをスクリプトの監視フォルダに設定する』というだけなのだが、『こうしたやり方もある』というアイデアの参考になれば幸いだ。なお、履歴機能そのものはGoogle Driveにもあるわけで、実用性については各自検討してもらいたい(苦笑
さて、スクリプトの実行方法だが、まずApp Centralから「DataSync for GoogleDrive」を導入、NAS上にGoogleドライブと同期するフォルダーを作成する。この下に監視フォルダー“Files”と履歴バックアップ先フォルダー“Backup”を設定する。チェックを行なう間隔(スリープ時間)は秒で指定し、今回はテストのために10秒としたが、1日間隔なら3600のように、適度な値に変更すればよい。
なお、上記の説明でわかるように、今回はあえて履歴バックアップ先もGoogle Drive上に設定している。本格的に活用するならファイルだけでなく、サブフォルダなども対象にしたほうが使い勝手がいいだろう。
history.pl
#!/usr/bin/perl
use strict;
use warnings;
use File::Copy;
my $maxloop = 24; #ループ回数上限
my $sleeptime =3600; #スリープ時間(秒)
my $target = "/volume1/home/admin/GoogleDrive/Files"; #監視対象のフォルダ
my $backup = "/volume1/home/admin/GoogleDrive/Backup/"; #バックアップ先
chdir($target);
my @file ="";
my $i=1;
while($i<=$maxloop){
print "LOOP\=$i\n";
@file = glob "*";
foreach my $f (@file){
if( -f $f){
my ($sec, $min, $hour, $day, $mon, $year) = localtime((stat($f))[9]);
$year = $year + 1900;
$mon = $mon + 1;
my $filename_backup=$backup.sprintf("%04d%02d%02d_%02d%02d%02d_",$year,$mon,$day,$hour,$min,$sec).$f;
if(!( -e $filename_backup )){
copy ($f,$filename_backup);
print "Backup : ".$f." to ".$filename_backup."\n";
}
}
}
sleep ($sleeptime);
$i++;
}
7日間更新がなかったファイルは削除する“時限タイマー”
ファイルの更新時刻を参照することができるなら、ということで7日間更新がないファイルを削除するスクリプトも作ってみた。
先の履歴バックアップと合わせて、『あまりにも古いバックアップを自動削除する』といった動作もできるだろう。なお、現在時刻の取得はNAS本体の時計を参照している。これが狂うと予期せぬ動作をする場合もあるので要注意。
スクリプトでは、“$obsoletespan”が削除までの秒数を指定している。7日間であれば3600(60秒×60分)×24(時間)×7(日)で7日間となる。監視対象のフォルダーは“Target”を指定している。
obsolete.pl
#!/usr/bin/perl
use strict;
use warnings;
my $maxloop = 24; #ループ回数上限
my $sleeptime =3600; #スリープ時間(秒)
my $target = "./Target/"; #監視対象のフォルダ
my $obsoletespan= 3600 * 24 * 7; #削除までの秒数(7日間)
chdir($target);
my @file ="";
my $i=1;
while($i<=$maxloop){
print "LOOP\=$i\n";
my $obsoletetime= time - $obsoletespan;
@file = glob "*";
foreach my $f (@file){
if( -f $f){
if( (stat($f))[9] < $obsoletetime ){
print "Obsolete : ".$f."\n";
unlink $f;
}
}
sleep ($sleeptime);
$i++;
}
}
アイデア次第でいろいろできる
以上、5つのPerlスクリプトを紹介してきた。そこまで作り込んだ内容ではないが、NAS+Perlスクリプトで何が自動化できそうか、アイデアの参考になれば幸いだ。
特にファイル管理は、各々“自分ルール”があるのではないだろうか。それを外部のツールに頼るとなると、なかなか思った通りに動いてくれるものが少ない。そうした時は、スクリプトを書いてしまうのが簡単で確実。そしてそれが、NASのように最終的なファイル管理デバイス上で自動化できるのならば、日々ファイル管理にかかっていた手間を大幅に短縮できるだろう。
【編集部からのお願い】
今回掲載したスクリプトを改良、あるいはNASで使うと便利そうなスクリプトが作成できましたら、当記事のFacebookページにコメントとしてお寄せください。なお、お寄せいただいたスクリプトについては、個別にご連絡のうえ、記事で紹介させていただく場合もあります。
[制作協力:ASUSTOR / ユニスター]