Perlで圧縮ファイルを再帰的に展開する方法

Perlで圧縮ファイルを再帰的に展開する方法

Posted at November 14,2014 1:55 AM
Tag:[Perl]

Perlで圧縮ファイルを再帰的に展開する方法を紹介します。

1.はじめに

仕事で、次のように入れ子になっているtar.gzファイルをすべて展開する必要が生じました。

test1.tar.gz
 ├ test2.tar.gz
 │ └ test4.tar.gz
 └ test3.tar.gz
   └ test5.tar.gz

ということで、Perlを使って圧縮ファイルを再帰的に展開する方法を考えてみました。

よりエレガントな解があるかもしれませんがとりあえず。

2.再帰的に展開するサンプル

次のようなコードを作ってみました。

#!/usr/bin/perl
 
use strict;
use File::Find;
 
my $dir = shift;
my @list;
 
find( \&unzip, $dir );
 
sub unzip {
    if (/(.*\.tgz|.*\.tar\.gz)/) {
        my $name = $1;
        my $file = "$File::Find::dir/$1";
        my @grep = grep /$file/, @list if @list;
        if ( !@grep ) {
            push @list, $file;
            my $result = `tar -zxvf $file`;
            find( \&unzip, $dir );
        }
    }
}

3.解説

File::Findは、再帰的にすべてのファイルを処理するためのモジュールです。

use File::Find;
…中略…
find( \&unzip, $dir );

find()の第1パラメータは関数のリファレンス、第2パラメータは処理したいトップディレクトリです。

呼び出された関数ではカレントディレクトリやファイル名を取得できます。

関数内の「$File::Find::dir」には実行中のカレントディレクトリが格納されています。

つまり、

    if (/(.*\.tgz|.*\.tar\.gz)/) {
        my $name = $1;
        my $file = "$File::Find::dir/$1";

とすることでトップディレクトリからのパスと、拡張子が「tgz」または「tar.gz」のファイル名を取得できます。

次に、後述する再帰呼び出しで同一ファイルに対する展開を避けるために、

        my @grep = grep /$file/, @list if @list;
        if ( !@grep ) {
            push @list, $file;

で配列に展開済のパス・ファイル名を保持しています。

最後にバッククォートを使ってtarコマンドでtar.gzファイルを展開し、展開したアーカイブのためにfindを再帰呼び出しします。

            my $result = `tar -zxvf $file`;
            find( \&unzip, $dir );

再帰呼び出しをしないと初回起動時に存在するディレクトリしか走査されませんので、ご注意ください。

チェックする拡張子を増やせばzipやgzファイルも同時に展開することが可能です。

関連記事
zenback
人気エントリー
トラックバックURL


コメントする
greeting

*必須

*必須(非表示)


ご質問のコメントの回答については、内容あるいは多忙の場合、1週間以上かかる場合があります。また、すべてのご質問にはお答えできない可能性があります。予めご了承ください。

太字イタリックアンダーラインハイパーリンク引用
[サインインしない場合はここにCAPTCHAを表示します]

コメント投稿後にScript Errorや500エラーが表示された場合は、すぐに再送信せず、ブラウザの「戻る」ボタンで一旦エントリーのページに戻り(プレビュー画面で投稿した場合は、投稿内容をマウスコピーしてからエントリーのページに戻り)、ブラウザをリロードして投稿コメントが反映されていることを確認してください。

コメント欄に(X)HTMLタグやMTタグを記述される場合、「<」は「&lt;」、「>」は「&gt;」と入力してください。例えば「<$MTBlogURL$>」は「&lt;$MTBlogURL$&gt;」となります(全て半角文字)