使用 Capture::Tiny 将 STDOUT 捕获到文件
Capture STDOUT to file with Capture::Tiny
我正在尝试将 STDOUT 捕获到具有 Capture::Tiny 的文件中。
为了给你一个更大的图景,我的最终目标是:
- 运行 命令行上的 Blender 进程
- 将日志捕获到文件句柄
- 观察文件句柄“增长”
- 将文件句柄的内容通过管道传输到 websocket,以便用户通过网页观看进度
我的计划是使用Capture::Tiny,以及this thread中提供的示例。
但是我停留在第 1 步:我可以像预期的那样捕获 STDOUT 和 STDERR:
use IO::File;
use Capture::Tiny qw/capture/;
$\ = "\n"; $, = "\t";
my $blender = '/home/simone/blender/blender-3.1.0-linux-x64/blender -b /home/simone/some_file.blend --python /home/simone/blender_scripts/some_script.py';
my ($stdout, $stderr, $exit) = capture {
system( $blender );
};
print join "\n", "STDOUT", $stdout =~ s/Time/Foobar/rg;
print '-' x 80;
print join "\n", "STDERR", $stderr;
print '-' x 80;
它产生了正确的输出,但是——据我所知——并没有让我看到它的进展。
这样做:
my $out_fh = IO::File->new("out_stdout.txt", "w+");
my $err_fh = IO::File->new("out_stderr.txt", "w+");
capture { qx/$blender/ } stdout => $out_fh, stderr => $err_fh;
留给我两个空文件。这是我稍后想看的两个文件。
我应该怎么做?有更好的(即:可行的)方法吗?
system
(或qx
)运行命令完成,然后return。您需要异步 运行 命令。 IPC::Run 是我对此类交互的首选解决方案。
capture { qx/$blender/ } stdout => $out_fh, stderr => $err_fh;
应该是
capture { system($blender) } stdout => $out_fh, stderr => $err_fh;
qx//
导致输出被捕获,覆盖 capture { }
.
创建的重定向
例如,
use strict;
use warnings;
use Capture::Tiny qw( capture );
open( my $out_fh, '>', 'out' ) or die $!;
open( my $err_fh, '>', 'err' ) or die $!;
my $cmd = <<'EOS';
perl -e'$| = 1; while ( 1 ) { CORE::say ++$i; sleep 1; }'
EOS
my $e;
capture { system($cmd); $e = $?; } stdout => $out_fh, stderr => $err_fh;
die( "Killed by signal ".( $e & 0x7F )."\n" ) if $e & 0x7F;
die( "Exited with error ".( $e >> 8 )."\n" ) if $e >> 8;
$ perl a.pl &
[1] 19051
$ cat out
1
2
3
$ cat out
1
2
3
4
5
$ kill %1
但是你在脚本中展示了自己处理信息的过程。 Capture::Tiny 不会帮助您做到这一点,至少在程序处于 运行 时不会。为此,您可以使用 IPC::Run.
use IPC::Run qw( run );
sub do_something_with_line {
print $_[0] =~ s/Time/Foobar/rg;
}
my $cmd = [ "perl", "-e", '$|=1; while ( 1 ) { CORE::say "Time ", ++$i; sleep 1; }' ];
my $buf = '';
run $cmd,
'>', sub {
$buf .= $_[0];
while ( $buf =~ s/^(.*\n)// ) {
do_something_with_line( );
}
};
my $e = $?;
do_something_with_line( $buf ) if length( $buf );
die( "Killed by signal ".( $e & 0x7F )."\n" ) if $e & 0x7F;
die( "Exited with error ".( $e >> 8 )."\n" ) if $e >> 8;
$ perl b.pl
Foobar 1
Foobar 2
Foobar 3
Foobar 4
Foobar 5
^C
(添加 '2>', ...
以使用 stderr 执行某些操作。)
我正在尝试将 STDOUT 捕获到具有 Capture::Tiny 的文件中。
为了给你一个更大的图景,我的最终目标是:
- 运行 命令行上的 Blender 进程
- 将日志捕获到文件句柄
- 观察文件句柄“增长”
- 将文件句柄的内容通过管道传输到 websocket,以便用户通过网页观看进度
我的计划是使用Capture::Tiny,以及this thread中提供的示例。
但是我停留在第 1 步:我可以像预期的那样捕获 STDOUT 和 STDERR:
use IO::File;
use Capture::Tiny qw/capture/;
$\ = "\n"; $, = "\t";
my $blender = '/home/simone/blender/blender-3.1.0-linux-x64/blender -b /home/simone/some_file.blend --python /home/simone/blender_scripts/some_script.py';
my ($stdout, $stderr, $exit) = capture {
system( $blender );
};
print join "\n", "STDOUT", $stdout =~ s/Time/Foobar/rg;
print '-' x 80;
print join "\n", "STDERR", $stderr;
print '-' x 80;
它产生了正确的输出,但是——据我所知——并没有让我看到它的进展。
这样做:
my $out_fh = IO::File->new("out_stdout.txt", "w+");
my $err_fh = IO::File->new("out_stderr.txt", "w+");
capture { qx/$blender/ } stdout => $out_fh, stderr => $err_fh;
留给我两个空文件。这是我稍后想看的两个文件。
我应该怎么做?有更好的(即:可行的)方法吗?
system
(或qx
)运行命令完成,然后return。您需要异步 运行 命令。 IPC::Run 是我对此类交互的首选解决方案。
capture { qx/$blender/ } stdout => $out_fh, stderr => $err_fh;
应该是
capture { system($blender) } stdout => $out_fh, stderr => $err_fh;
qx//
导致输出被捕获,覆盖 capture { }
.
例如,
use strict;
use warnings;
use Capture::Tiny qw( capture );
open( my $out_fh, '>', 'out' ) or die $!;
open( my $err_fh, '>', 'err' ) or die $!;
my $cmd = <<'EOS';
perl -e'$| = 1; while ( 1 ) { CORE::say ++$i; sleep 1; }'
EOS
my $e;
capture { system($cmd); $e = $?; } stdout => $out_fh, stderr => $err_fh;
die( "Killed by signal ".( $e & 0x7F )."\n" ) if $e & 0x7F;
die( "Exited with error ".( $e >> 8 )."\n" ) if $e >> 8;
$ perl a.pl &
[1] 19051
$ cat out
1
2
3
$ cat out
1
2
3
4
5
$ kill %1
但是你在脚本中展示了自己处理信息的过程。 Capture::Tiny 不会帮助您做到这一点,至少在程序处于 运行 时不会。为此,您可以使用 IPC::Run.
use IPC::Run qw( run );
sub do_something_with_line {
print $_[0] =~ s/Time/Foobar/rg;
}
my $cmd = [ "perl", "-e", '$|=1; while ( 1 ) { CORE::say "Time ", ++$i; sleep 1; }' ];
my $buf = '';
run $cmd,
'>', sub {
$buf .= $_[0];
while ( $buf =~ s/^(.*\n)// ) {
do_something_with_line( );
}
};
my $e = $?;
do_something_with_line( $buf ) if length( $buf );
die( "Killed by signal ".( $e & 0x7F )."\n" ) if $e & 0x7F;
die( "Exited with error ".( $e >> 8 )."\n" ) if $e >> 8;
$ perl b.pl
Foobar 1
Foobar 2
Foobar 3
Foobar 4
Foobar 5
^C
(添加 '2>', ...
以使用 stderr 执行某些操作。)