busybox.pl

30分プログラム、その20。記念すべき20回目なのに、結構手抜き。

head+tail+grep+cat+echoなプログラム。BusyBox風味。

$ ln -s busybox.pl head
$ ln -s busybox.pl tail
$ ln -s busybox.pl grep
$ ln -s busybox.pl cat
$ ln -s busybox.pl echo

$ perl head busybox.pl
#!/usr/bin/env perl
use strict;
use warnings;
....

$ perl tail 
....
    no strict 'refs';
    $0->(@ARGV);
}

$ perl grep perl *
busybox.pl:#!/usr/bin/env perl
cat:#!/usr/bin/env perl
cgi.pl:#!/usr/bin/env perl
echo:#!/usr/bin/env perl

$ perl cat busybox.pl
#!/usr/bin/env perl
use strict;
use warnings;
....

$ perl echo TMTOWTDI
TMTOWTDI

要するに1つのファイルなのに、シンボリックリンクの名前によって動作が変わるPerlプログラム。
本来は組み込みOSで、1つの実行ファイルでlsからrmまでを実現したいときに使う手法。だから、Perlで再現する理由はこれっぽっちもない。
うん、特にやることが思いつかなくてhead単体だと時間があまりすぎるからbusyboxっぽくしただけなんだよね。

#!/usr/bin/env perl
use strict;
use warnings;
use Data::Dumper;
 
sub p(@){
    print Dumper(@_);
}
 
sub head{
    my ($filename) = @_;
    open(FILE,$filename);
    while(<FILE>){
	last if $. > 10;
	print;
    }
    close(FILE);
}
 
sub tail{
    my ($filename) = @_;
    open(FILE,$filename);
    my @lines = (<FILE>)[-10..-1];
    print @lines;
    close(FILE);
}
 
sub grep{
    my ($pattern,@filenames) = @_;

    for my $filename (@filenames){
	open(FILE,$filename);
	while(<FILE>){
	    printf("%s:%s",$filename,$_) if /$pattern/
	}
	close(FILE);
    }
}
 
sub cat{
    for my $filename (@_){
	open(FILE,$filename);
	my @lines = <FILE>;
	print @lines;
	close(FILE);
    }
}
 
sub echo{
    print join(' ',@_),"\n";
}
 
{
    no strict 'refs';
    $0->(@ARGV);
}
  • ファイル操作こそPerlの真骨頂、のはずが今ひとつ。$_が使いこなせないなあ
  • ああ、似たパターンがいっぱいある(foreachとか)。高階関数が欲しい
  • no strict 'refs'してるけど、いいのかな?一応、範囲は限定してるけど
  • やっぱり、Data::Dumperは最高