perlで宝探し


映画『バクマン。』(2015)
頑張ってる人を見ると熱くなりますねえ。夢があって若くて友情で努力で勝利で最高です。何か自分も頑張りたくなります。絵でも描いてみようか。

ディレクトリをたくさん作って宝探ししてみます。

takk@deb8:~$ mkdir a;cd a
takk@deb8:~/a$ mkdir {1..9999}
takk@deb8:~/a$ 

ディレクトリを9999個用意したら、お宝をどこかのディレクトリにtouchで入れます。treasureというファイル名です。

takk@deb8:~/a$ touch `ls | sort -R | head -1`/treasure

このtreasureというファイルを見つけるのは、findを使えば簡単ですね。

takk@deb8:~/a$ find -name treasure
./7326/treasure
takk@deb8:~/a$ 

では、少し複雑にします。木(tree)があるディレクトリの3番目に大きい数字の箱(box)にお宝が入っているものとします。

takk@deb8:~/a$ rm -rf *
takk@deb8:~/a$ mkdir {1..999}
##takk@deb8:~/a$ for i in `find -type d`;do touch $i/box{1..9};done
takk@deb8:~/a$ for i in `find -type d`;do for j in {1..10};do touch $i/box$RANDOM;done;done
takk@deb8:~/a$ 
takk@deb8:~/a$ a=`ls | sort -R | head -1`
takk@deb8:~/a$ touch $a/tree
takk@deb8:~/a$ 

さて、どう探しましょうか。
かなりfindを使い込んでいれば簡単でしょうけど、ベースのperlスクリプトがあれば、少し改造するだけで良いです。
find2perlを使って、findをperlスクリプトで実現してみましょう。

takk@deb8:~/a$ find2perl -name tree > hunter.pl
takk@deb8:~/a$ 

hunter.plの内容です。

     1	#! /usr/bin/perl -w
     2	    eval 'exec /usr/bin/perl -S $0 ${1+"$@"}'
     3	        if 0; #$running_under_some_shell
     4	
     5	use strict;
     6	use File::Find ();
     7	
     8	# Set the variable $File::Find::dont_use_nlink if you're using AFS,
     9	# since AFS cheats.
    10	
    11	# for the convenience of &wanted calls, including -eval statements:
    12	use vars qw/*name *dir *prune/;
    13	*name   = *File::Find::name;
    14	*dir    = *File::Find::dir;
    15	*prune  = *File::Find::prune;
    16	
    17	sub wanted;
    18	
    19	
    20	
    21	# Traverse desired filesystems
    22	File::Find::find({wanted => \&wanted}, '.');
    23	exit;
    24	
    25	
    26	sub wanted {
    27	    /^tree\z/s
    28	    && print("$name\n");
    29	}
    30	

26行目から29行目の内容を変えてやれば、findの条件が変更できます。

 26 sub wanted {
 27     if(/^tree\z/){
 28         print "$dir\n";
 29         system "ls \$dir | grep box | sort -tx -nrk2 | sed -n 3p";
 30     }
 31 }

実行すると該当するファイルが見つかります。

takk@deb8:~/a$ perl hunter.pl
./197
box26344
takk@deb8:~/a$ 

この結果はあってるでしょうか。確認してみます。

takk@deb8:~/a$ ls ./197/box* | sort -tx -nrk2
./197/box32256
./197/box32179
./197/box26344
./197/box17344
./197/box15881
./197/box15659
./197/box14880
./197/box8816
./197/box7819
./197/box4491
takk@deb8:~/a$ ls ./197/box* | sort -tx -nrk2 | sed -n 3p
./197/box26344
takk@deb8:~/a$ 

sortの-tオプションで指定しているxは、セパレータとしてboxのxの文字(数字の直前の文字)を指定しています。

コメント

タイトルとURLをコピーしました