読者です 読者をやめる 読者になる 読者になる

tweeeetyのぶろぐ的めも

アウトプットが少なかったダメな自分をアウトプット<br>\(^o^)/

perlのglobでファイル一覧とかtree構造とかを作ってみるテスト。ついでに<>(fileglob)もおためし

はじめに

プログラムかなんかでファイルの一覧を取得したいなーってときありますよね。
一覧だじゃなくて階層ごと取りたいってこともあるとかないとか。

そこでファイルの一覧を取得できるperlの「glob」を使ってみます
参考はこちらhttp://d.hatena.ne.jp/perlcodesample/20080529/1212075850

構文は以下

my $path = "/hoge/hoge/hoge/*"; # 一覧を取得したいディレクトリのパス
my @files_list = glob "$path";
もしくは
my @files_list = <$path>;

いきなりの補足ですが<>でglobと同じらしいです。
ダイアモンド演算子と同じ?っていうのはglobがよくわかってないのでわかりませんw

さっそくプログラムを書いてテスト

試すディレクトリの中は適当にファイルとディレクトリを作ってみました。こんな感じ

# tree glob_test_dir
glob_test_dir
|-- a.file
|-- a.txt
|-- any_dir_01
|   |-- aaaa.txt
|   `-- bbbb.txt
|-- any_dir_02
|-- any_file
|-- b.file
|-- b.txt
|-- c.txt
|-- test01.text
|-- test02.text
`-- test03.text

プログラムはglob_test_dirがいるところと同ディレクトリに作るとします

すべて取得してみる

glob_all.pl

my $path  = "./glob_test_dir/*";
my @files = glob $path;
warn Dumper @files;

結果

# perl glob_all.pl
$VAR1 = './glob_test_dir/a.file';
$VAR2 = './glob_test_dir/a.txt';
$VAR3 = './glob_test_dir/any_dir_01';
$VAR4 = './glob_test_dir/any_dir_02';
$VAR5 = './glob_test_dir/any_file';
$VAR6 = './glob_test_dir/b.file';
$VAR7 = './glob_test_dir/b.txt';
$VAR8 = './glob_test_dir/c.txt';
$VAR9 = './glob_test_dir/test01.text';
$VAR10 = './glob_test_dir/test02.text';
$VAR11 = './glob_test_dir/test03.text';

フォルダも一覧の中に含まれてます

aではじまるファイルだけ取得、.textだけ取得とかやってみる

glob_specific.pl

# aではじまるやつ
my $path  = "./glob_test_dir/a*";
my @files = glob $path;
warn Dumper @files;

# .textで終わるやつ
my $path  = "./glob_test_dir/*.text";
my @files = glob $path;
warn Dumper @files;

結果

# perl glob_specific.pl
$VAR1 = './glob_test_dir/a.file';
$VAR2 = './glob_test_dir/a.txt';
$VAR3 = './glob_test_dir/any_dir_01';
$VAR4 = './glob_test_dir/any_dir_02';
$VAR5 = './glob_test_dir/any_file';

$VAR1 = './glob_test_dir/test01.text';
$VAR2 = './glob_test_dir/test02.text';
$VAR3 = './glob_test_dir/test03.text';

<>を使ってみる

glob_kigou.l

# これはダメらしい ※理由は特に調べてません
my $path  = "./glob_test_dir/*";
my @files = <$path>;
warn Dumper @files;

# こっちはOK
my $path  = "glob_test_dir/*";
my @files = <./$path>;
warn Dumper @files;

結果

# perl glob_kigou.pl
readline() on unopened filehandle at glob_kigou.pl line 8.
Warning: something's wrong at glob_kigou.pl line 9.

$VAR1 = './glob_test_dir/a.file';
$VAR2 = './glob_test_dir/a.txt';
$VAR3 = './glob_test_dir/any_dir_01';
$VAR4 = './glob_test_dir/any_dir_02';
$VAR5 = './glob_test_dir/any_file';
$VAR6 = './glob_test_dir/b.file';
$VAR7 = './glob_test_dir/b.txt';
$VAR8 = './glob_test_dir/c.txt';
$VAR9 = './glob_test_dir/test01.text';
$VAR10 = './glob_test_dir/test02.text';
$VAR11 = './glob_test_dir/test03.text';

※全体的にshebangやuse strictとかは省いて書いてます。

glob使ってツリー構造を自分で作ってみる

globでファイルの一覧が取得できましたがディレクトリも含まれるので自前で判定します。
判定して除外だけとか面白くないのでツリー構造をperlの変数で作ってみました
glob_tree.pl

#!/usr/bin/perl

use strict;
use warnings;
use Data::Dumper;

my $arg = $ARGV[0]; 
my $scan_dir_path = ($arg) ? $arg :'.';
my $tree;
$tree = &scan_dir($scan_dir_path);

# 下位階層のディレクトリもすべてglobで捜査して$tree変数に格納
sub scan_dir {
  my $scan_dir_path = shift;
  # 念のため後方スラッシュ削除&"/*"を付けたし
  $scan_dir_path =~ s/\/$//;
  $scan_dir_path = $scan_dir_path . "/*";
  
  my $tree = [];
  my @pathes = glob $scan_dir_path;
  foreach my $path (@pathes)
  {
    if( -d $path )
    {
      # pathがディレクトリの場合は再帰
      my $tmp_tree = {};
      $tmp_tree->{$path} = &scan_dir($path);
      push @$tree, $tmp_tree;
    }
    else
    {
      push @$tree, $path;
    }
  }
  return $tree;
}
warn Dumper $tree;
1;

結果

perl list_dir_and_file.pl "./glob_test_dir/"
$VAR1 = [
          './glob_test_dir/a.file',
          './glob_test_dir/a.txt',
          {
            './glob_test_dir/any_dir_01' => [
                                              './glob_test_dir/any_dir_01/aaaa.txt',
                                              './glob_test_dir/any_dir_01/bbbb.txt'
                                            ]
          },
          {
            './glob_test_dir/any_dir_02' => []
          },
          './glob_test_dir/any_file',
          './glob_test_dir/b.file',
          './glob_test_dir/b.txt',
          './glob_test_dir/c.txt',
          './glob_test_dir/test01.text',
          './glob_test_dir/test02.text',
          './glob_test_dir/test03.text'
        ];
tips

globは危険という記事も見つけたので合わせてのせておきます
外部入力とかありそーなら気をつけましょうという感じでしょうか。
Perl の危険な関数