STDOUT を置き換えてると IPC::Open3 でうまくいかなかった
コマンドを実行してその結果を取得する際に,IPC::Open3::open3() を使おうと思いました。由あって STDOUT を置換していたんですが,うまくいきませんでした。
って意味ふめーなので具体的なコードで書くと,
#!/usr/bin/perl use strict; use warnings; use Carp; use Symbol; use IPC::Open3; warn 'normal'; run(); my $output = ''; { open my $handle, '>', \$output or confess $!; local *STDOUT = $handle; warn 'replaced'; run(); close $handle; } sub run { my ($ph_i, $ph_o, $ph_e) = (gensym, gensym, gensym); my $pid = open3($ph_i, $ph_o, $ph_e, qw'/bin/ls -l /'); confess $! if ! defined $pid or $pid <= 0; close $ph_i; local $/; my $out = <$ph_o>; my $err = <$ph_e>; close $ph_o; close $ph_e; waitpid $pid, 0; }
なコードを実行すると,
normal at test.pl line 9. replaced at test.pl line 18. total 45 drwxr-xr-x 2 root root 4096 Feb 10 04:05 bin ... (後略)
のようになります。つまり,*STDOUT を置換した後だと,標準出力をトラップできずに画面にでてしまう,という。
標準出力をオープンしなおしたりしようといろいろやってたんですが,あんまり芳しくなかったです。で,最終的に動いたのが,
sub run { my ($ph_i, $ph_o, $ph_e) = (gensym, gensym, gensym); use IO::Handle; local *STDOUT = IO::Handle->new_from_fd(1, 'w'); my $pid = open3($ph_i, $ph_o, $ph_e, qw'/bin/ls -l /'); ... (後略)
みたく,IO:Handle の fd を使って 1 番(標準出力)として設定し直す方法でした。
これで,無事,
normal at test.pl line 9. replaced at test.pl line 18.
となり,$out 等に取得できました。