将stdout和stderr管道传入文件的子程序

时间:2018-04-23 10:46:19

标签: perl

如果我有一个名为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;

有没有办法将支持文件的冗长处理以可重用的方式放入模块中? (支持文件应由用户发送给程序维护者。)

注意:上述解决方案也适用于simplecalc.pl 4 0 0 1,导致除法为0.在主程序使用的任何模块中捕获die并将die-msg写入支持 - 文件是一个重要的功能。

2 个答案:

答案 0 :(得分:2)

我猜你正在寻找select,它会更改printsay中的默认文件处理程序。并且END在程序结束之前运行。

use v5.10; use warnings; use strict;
my($OK,$UNKNOWN)=(1,0);

my($filename, $endmsg, $exit) = ('my.log', 'OK', $OK);
END { say $endmsg }
my $DEFAULT_FH=select;  #select returns current default filehandler (often STDIN)
if( rand()<0.5){        #half the time, for test
    open my $FH, '>>:utf8', $filename or die;
    $endmsg = qq{support-info sucessfully written into $filename};
    $exit = $UNKNOWN;
    select $FH;
}

print "Something something\n";
say   "Something say something more";

if(1){
    select $DEFAULT_FH;     #or just: select STDIN
}
exit $exit;

答案 1 :(得分:2)

我提出这个问题想要控制来自模块的两个流的重定向。

像这个基本的例子吗?

<强> 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;

控制台上的输出是(对齐)

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有两行。 (如果它们在控制台上结束,则可以轻松找到它们。)

此示例中管理文件句柄的责任在于调用者。

这应该通过各种错误检查,subs中的选项(仅重定向一个流,或者每个都重定向到自己的文件等)以及可能的一些便利例程来完成。