2009年02月10日 01:00 [Edit]

perl - open my $fh, "comand |"; # はモダンじゃない

モダンPerl入門」発売記念ということで、同書を補足するentryを。


同書でちょっと残念だったのが、[5.2 外部コマンドの実行]。あまりモダンではないのだ。

P. 141
system("/sbin/wget", "http://example.com");

これはいいのだが、以下がちょっとまずい。

my $output = `/bin/ls tmp`;
open(my $fh, '| cat -v');

これ、何がまずいか、というと、コマンド実行の際に/bin/shを使ってしまうのだ。そのおかげでcommand < from > to 2&>1のようなリダイレクトも使えるなどの利点もあるのだが、

my $arg    = shift;
my $result = `cmd $arg`;

のようなコードがあったとして、$arg`rm -rf /`が入っていたりすると、期待通りイヤな結末が待っている。幸い同書では変数を渡す例はなかったが、より安全な方法を紹介しておくに超したことはない。しかも、モダンPerlならば手間も増えないのである。

Perl 5.8以前のPerlにおいて、

open(my $fh, '| cat -v');

のより安全な書き方は以下の通りだった。

open my $fh, '|-' or exec qw/cat -v/ or die $!;

偏執狂的にやると、

perldoc perlipc
use English '-no_match_vars';
# add error processing as above
$pid = open(KID_TO_READ, "-|");

if ($pid) {   # parent
    while (<KID_TO_READ>) {
        # do something interesting
    }
    close(KID_TO_READ) || warn "kid exited $?";

} else {      # child
    ($EUID, $EGID) = ($UID, $GID); # suid only
    exec($program, @options, @args)
        || die "can't exec program: $!";
    # NOTREACHED
}

となっていた。しかし、Perl 5.8以降では、以下のようにすっきりと書ける。

open my $fh, '|-', qw/cat -v/ or die $!;

書き込むときには'-|',読み込むときには'|-'を「ファイル名」として指定し、あとは実行したいコマンドと引数をリストとして渡す。shellは全く経由しない。

それでも面倒なら、以下のようにしてもいいだろう。

sub open_pipe2read{
   my $cmd = shift;
   open my $pipe, '-|', $cmd, @_ or die "$cmd: $!";
   $pipe;
}

sub open_pipe2write{
   my $cmd = shift;
   open my $pipe, '|-', $cmd, @_ or die "$cmd: $!";
   $pipe;
}

sub safeqx {
    my $pipe = open_pipe2read @_;
    my @result;
    while ( defined( my $line = <$pipe> ) ) {
        push @result, $line;
    }
    close $pipe or warn "status: $?";
    wantarray ? @result : join( $/, @result );
}

地味なところも、モダンに行きたいものである。

Dan the Modern Perl Monger

See Also:


この記事へのトラックバックURL

この記事へのトラックバック
面白い。 ターミナル内で画像を表示するコマンド - デー でもスクリプトが「重い」。
perl - 勝手に添削 - ターミナル内で画像を表示するコマンド【404 Blog Not Found】at 2010年08月04日 13:26
気になった。 404 Blog Not Found:perl - open my $fh, "comand |"; # はモダンじゃない 書き込むときには’-|’,読み込むときには’|-’を「ファイル名」として指定し、あとは実行したいコマンドと引数をリストとして渡す。 例えば外部コマンドを実行し、その結果...
[perl]openの -| と |-【だるろぐ】at 2009年11月06日 07:43
Perlでtaskkill for Windows - 燈明日記 今回に限っては、openで3つの引数『open(my $fh, ' ファイルじゃないのでなります。 pipeの場合は次のようにやればHAPPY open my $pipe, '-|', $cmd, @args or die $!; あと、systemもlistで渡したほうがベターです system ...
openは激しく柔軟【にひりずむ::しんぷる】at 2009年06月04日 13:04
この記事へのコメント
>書き込むときには'-|',読み込むときには'|-'を

逆だ。
Posted by springer2005 at 2010年08月22日 10:07
こういう指摘をする暇があるのなら、自身がもっとモダンなperl本を書かれたらいいんじゃないっすかね? 是非読んでみたいものです。
Posted by ダンさんが at 2009年02月11日 07:24
まあ世の中には Malbolgeや Befungeなんぞに萌えるハイビクタンな人たちもいっぱい(?)いるわけで。
というか多様性を許容できなくなってきたらじじいへの第一歩だな。さようなら。
Posted by shou at 2009年02月10日 11:16
ジリビンwwww
ジリ貧はじりひんって読むんだ。

で海外がどうしたって?それがどうした?舶来崇拝主義か?
独自の進化を遂げて何が悪い?
Posted by パッパラー at 2009年02月10日 08:37
Perlって海外じゃジリビンじゃん。
なんで日本ではいまだにこんなのに萌えてるのがいるわけ?
ガラパゴス諸島?
Posted by パッパラパーのパール at 2009年02月10日 04:14