将stdout和stderr管道传输到文件的子例程 [英] Subroutine for piping stdout and stderr into file
问题描述
如果我有一个名为 simplecalc.pl
的程序:
If I have a program called simplecalc.pl
:
use v5.10;
use warnings;
use strict;
# SIMPLE CALCULATOR
# Usage: simplecalc.pl <n1> <n2> [<verbose> <logswitch>]
# Example Usage:
# normal usage : simplecalc.pl 4 2
# verbose usage : simplecalc.pl 4 2 1
# support-case usage: simplecalc.pl 4 2 0 1
my($OK,$UNKNOWN)=(0,3);
my($filename, $endmsg, $exit) = ('my.log', undef, undef);
my($n1, $n2, $DEBUG, $GET_SUPPORT_FILE) = @ARGV;
# Handling of the support-file starts here ===============================
*ORIGINAL_STDOUT = *STDOUT;
if ($GET_SUPPORT_FILE) {
$DEBUG = 1;
$endmsg = "support-info sucessfully written into $filename";
$exit = $UNKNOWN;
# redirect stdout and stderr
open my $stdout_txt, '>>:utf8', "$filename";
*STDOUT = $stdout_txt;
open STDERR, '>&STDOUT';
} else {
$endmsg = "Finnished calculation - good bye.";
$exit = $OK;
}
END {
select *ORIGINAL_STDOUT;
say $endmsg;
};
# end of support-file handling ============================================
say STDERR "INFO: got $n1 and $n2 from the commandline" if $DEBUG;
say "Hello, let me calc the quotient from $n1 trough $n2 for you ...";
my $quotient = $n1 / $n2;
say "Quotient: $quotient";
exit $exit;
是否有一种方法可以将对支持文件的冗长处理以可重用的方式放入模块中?(该支持文件应由用户发送到程序维护者.)
Is there a way to put the lengthy handling of the support-file in a reusable way into a module? (The support-file is meant to be sent by the user to the program-maintainer.)
注意:上面的解决方案也适用于 simplecalc.pl 4 0 0 1
,这导致除法槽为0.在主模块使用的任何模块中捕获 die
-programm并将die-msg写入支持文件是一个重要功能.
Note: The above solution also works for simplecalc.pl 4 0 0 1
which results in a division trough 0. Catching a die
in any module used by the main-programm and write the die-msg into the support-file is an important feature.
推荐答案
我提出了一个问题,希望控制模块中两个流的重定向.
I take the question to want to control redirection of both streams from a module.
像这样的基本示例吗?
RedirectStreams.pm
package RedirectStreams;
use warnings;
use strict;
use Exporter qw(import);
our @EXPORT_OK = qw(redirect_streams restore_streams);
our ($stdout, $stderr) = (*STDOUT, *STDERR);
sub redirect_streams {
my ($handle) = @_;
*STDOUT = $handle;
*STDERR = $handle;
}
sub restore_streams {
*STDOUT = $stdout;
*STDERR = $stderr;
}
1;
main.pl
use warnings;
use strict;
use RedirectStreams qw(redirect_streams restore_streams);
my $logfile = shift @ARGV || 'streams.log';
say "Hello from ", __PACKAGE__;
warn "WARN from ", __PACKAGE__;
open my $fh, '>', $logfile;
redirect_streams($fh);
say "\tHi to redirected";
warn "\tWARN to redirected";
restore_streams();
say "Hi to STDOUT again";
warn "WARN in main again";
open my $fh_other, '>', 'other_' . $logfile;
redirect_streams($fh_other);
say "STDOUT redirected to another";
warn "STDERR redirected to another";
close $_ for $fh, $fh_other;
控制台上的输出(对齐)
Output on console is (aligned)
Hello from main
WARN from main at ... line 18.
Hi to STDOUT again
WARN in main again at ... line 29.
文件 streams.log
具有
Hi to redirected
WARN to redirected at ... line 24.
和 other_streams.log
有两行.(如果在控制台上收起来,则可以轻松地发现它.)
and other_streams.log
has its two lines. (Tabbed to spot easily if they wind up on console.)
在此示例中,管理文件句柄的责任在于调用者.
The responsibility for managing filehandles in this example rests on the caller.
这应该通过所有类型的错误检查,子选项(仅将一个流或每个流重定向到其自己的文件等)以及可能的其他一些便利例程来完成.
This should be completed with all manner of error checking, options in subs (redirect only one stream, or each to its own file, etc), and probably a few more convenience routines.
请注意,我们的$ stdout = * STDOUT
创建别名.
保存 STDOUT
以便以后恢复的另一种方法是复制它,
Another way to preserve STDOUT
for later restoration is to duplicate it,
open my $stdout, '>&', STDOUT;
这将创建一个独立的文件句柄,作为 STDOUT
的副本(这里我们只需要),该文件句柄不受 STDOUT
的更改(或关闭)的影响.有关示例用法,请参见这篇文章.
This creates an independent filehandle, made as a duplicate of STDOUT
(what is all we need here), which is unaffected by changes (or closure) of STDOUT
. See this post for an example use.
这篇关于将stdout和stderr管道传输到文件的子例程的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!