Perlでファイルを自動的にコピーしてみる

by

スクリーンショット 2016-08-24 14.50.27

はじめに

プログラマの小林です。
本日は、ファイルを自動的に目的のディレクトリに展開する処理について
簡単に説明したいと思います。

最近Androidの案件で、リソースファイルを
以下のようなディレクトリ構成でいただくことがありました。
resource_parts
|- drawable-hdpi
|- drawable-xhdpi
|- drawable-xxhdpi
|- drawable-xxxhdpi
resource_background
|- drawable-hdpi
|- drawable-xhdpi
|- drawable-xxhdpi
|- drawable-xxxhdpi
これだけの数なら手動でも問題はないのですが、
実際は「Aの画面の画像」「Bの画面の画像」などのように
渡されます。これだと種類が多くなってきた時に
コピーのミスや不足が発生してしまいます。
なので、スクリプトファイルで自動的にファイルのコピーをするようにしました。

今回の実行環境は
・Mac OS X 10.11
・Perl 5.18
となっています。

 

Perl

今回使用した言語はPerlです。
Perlは言語の文法レベルで正規表現を使用できる機能が含まれています。
これによって、ディレクトリとファイル名のマッチング処理を簡単に記述することができます。

 

スクリプトファイル

それではファイルの内容を見ていきましょう。
ファイルの名前はcpy_files.plとしておきます。

#!/usr/bin/perl
use strict;
use warnings;

use Cwd;

use constant {
  # 展開先のリソースフォルダの絶対パス
  DEPLOY_TARGET_DIRECTORY => "/path/to/resource/folder/res",
  # 展開先にあるdrawableリソースフォルダ名
  DEPLOY_TARGET_PATTERN => "drawable-[x]*hdpi",
};

######## メイン処理
my $currentDir = Cwd::getcwd();
# ファイルをプロジェクトディレクトリにコピー
deployFiles($currentDir);
######## メイン処理 終わり

まずはメイン処理です。
ソース内でのディレクトリ名やパターンの記述は
このように定数にまとめておいたほうがいいです。
deployFilesで実際の処理を行っています。

 

ディレクトリの走査

次にディレクトリを走査する部分を見ていきましょう。

sub deployFiles {
  my $currentDir = shift;
  my @list = ();

  #カレントディレクトリの一覧を取得
  opendir(DIR, $currentDir) or die("ディレクトリを取得できませんでした:$currentDir ($!)");
  @list = readdir(DIR);
  closedir(DIR);

  foreach my $dir (sort @list) {
    # "."と".."に対しては処理しない
    next if($dir =~ /^\.{1,2}$/);
    #ディレクトリのみにマッチ
    if(-d "$currentDir/$dir") {
      # パターンの後に自分と同じ名前のディレクトリがあるかどうか検査する
      if(-d DEPLOY_TARGET_DIRECTORY."/$dir") {
        copyFiles($currentDir, $dir);
      }

      # 自分の下のディレクトリもプロジェクトに展開する
      deployFiles("$currentDir/$dir");
    }
  }
}

deployFilesの処理内容です。ここではディレクトリを走査して、
ターゲットのディレクトリ(drawable-xhdpiなど)と同じ名前のディレクトリかどうか
比較をしています。
一致したディレクトリがあった場合、その中にあるファイルを
copyFilesサブルーチンで全てコピーします。
また、再帰的に自分の下にあるディレクトリも走査します。

 

ファイルの展開

次にファイルをコピーする部分を見ていきましょう。

sub copyFiles {
  my $currentDir = $_[0];
  my $targetDir = $_[1];
  my @list = ();
  # ディレクトリ内のディレクトリ・ファイルを取得
  opendir(DIR, "$currentDir/$targetDir") or die("ディレクトリを取得できませんでした:$currentDir/$targetDir ($!)");
  @list = readdir(DIR);
  closedir(DIR);

  foreach my $file (sort @list) {
    # "."と".."と隠しファイルに対しては処理しない
    next if($file =~ /^\.{1,2}.*$/);
    #ファイルのみにマッチ
    if(-f "$currentDir/$targetDir/$file") {
      copyFile($currentDir, $targetDir, $file);
    }
  }
}

sub copyFile {
  my $currentDir = $_[0];
  my $targetDir = $_[1];
  my $file = $_[2];

  my $cur = "$currentDir/$targetDir/$file";
  my $tar = DEPLOY_TARGET_DIRECTORY."/$targetDir/$file";
  open(OLD, "$cur");
  open(NEW, ">", "$tar");
  while(<OLD>) {
    print NEW $_;
  }
  close(OLD);
  close(NEW);
}

適切な名前のディレクトリを発見したので、その中にあるファイルを全てコピーします。
ファイルが存在しない場合、新規に作成され、既に存在している場合は
コピー元のファイルで上書きされます。

以上が書き終わったら、ターミナルからスクリプトのあるディレクトリに移動して
$perl cpy_files.pl
で実行できます。

 

まとめ

以上がPerlによるファイルコピー処理の自動化になります。
このように、かなり少ない行数でファイル名のマッチングとコピーが
書けるようになっています。
皆さんも仕事で「手動でやると大変だな」と思うことがあれば、
スクリプトでどんどん自動化・効率化していきましょう!

 

小林良
2014年10月にEDAで1ヶ月間インターン研修を受けた縁で
2016年4月入社。入社前は専門学校でプログラムを専攻。
好きな言語はC++、グラフィックスAPIはOpenGL。
最近はマルチスレッドのパターンを勉強中。

Egg Device Application

東京品川のスマホアプリ開発会社です。
一般アプリ、業務用アプリからVRまで開発可能。

ライター一覧

求人情報

スマホアプリ開発の
相談を受け付けています

メールでのご相談

お電話でのご相談
TEL 03-5422-7524
平日10:00~18:00