Perlから外部コマンドを実行する
TIME rest time current/total
TopicsPlaceHolder

Perlから外部コマンドを実行する

Gotanda.pm #8

Mar 30th, 2016

Profile

songmu

Mackerel Logo

 

最近作ったもの

Perlで外部コマンド実行

ケアすべきこと

バッククオート

標準出力を雑に取りたい時に便利。標準出力を補足し、出力は出さない。パイプとかリダイレクトとかできる。(shell経由になる)

$out = `perl -E 'say "Hello"'`;
$out = qx{perl -E 'warn "Hello\n"' 2>&1};
$exit = $? >> 8;

system関数

配列を渡すことでshell経由にならない。出力はそのまま。

my $ret = system('perl', '-E', 'say "Hello"');
# $ret には $? と同じ値が入ってくる
if ($ret != 0) {

}
if ($? == -1) {
    print "failed to execute: $!\n";
}
elsif ($? & 127) {
    printf "child died with signal %d, %s coredump\n",
        ($? & 127),  ($? & 128) ? 'with' : 'without';
}
else {
    printf "child exited with value %d\n", $? >> 8;
}

IPC::Cmd

IPC::Cmd was first released with perl v5.9.5

標準モジュール!

use IPC::Cmd qw/run/;
my ($ok, $err, $full_buf, $stdout_buf, $sederr_buf) = run('perl', '-E', 'say "Hello"');

コマンド出力は出しつつ、内容をcaptureしたい

teeコマンドを使う

お手軽

open(STDOUT, '| tee "' . $tmpfile . '"');
open(STDERR, ">&STDOUT");
system('...');

fork && exec

pipe my $logrh, my $logwh or die "failed to create pipe:$!";
unless (my $pid = fork) {
    if (defined $pid) {
        # child process
        close $logrh;

        open STDERR, '>&', $logwh or die "failed to redirect STDERR to logfile";
        open STDOUT, '>&', $logwh or die "failed to redirect STDOUT to logfile";
        close $logwh;
        exec 'perl', '-E', '....'; ## ここでコマンド実行
        die "exec(2) failed:$!";
    }
    else {
        close $logrh;
        close $logwh;
        warn "fork(2) failed:$!\n" unless defined $pid;
    }
}
else {
    close $logwh;
    my $buf = '';
    $buf .= $_ while <$logrh>;
    close $logrh;
}

PerlIO::Util

use PerlIO::Util;
open my $fh, ...;
$fh->push_layer(tee => *STDOUT);
$fh->push_layer(tee => \$out);

use Capture::Tiny

my ($stdout, $stderr) = tee {
    ...
};

以上

We are Hiring

hatena