我有一个perl脚本,用于处理子进程。
sub my_exec{
my($args,$stdout, $stderr) = @_;
my $processes = fork();
die("Cant fork") unless defined($processes);
if(processes == 0){
if(defined $stdout){
close(STDOUT);
open STDOUT, $stdout;
}
if(defined $stderr){
close(STDERR);
open STDERR, $stderr;
}
exec @$args;
}else{
...
}
}
我的主要问题是我想在stderr的每一行输出中添加一个时间戳。我想知道是否可以在这里完成。正如你所看到的,stderr并不总是被改变。我假设我可以通过某种管道来做到这一点?我还想重定向父脚本(守护进程,stdout和stderr重定向到文件)也使用时间戳。
由于
答案 0 :(得分:2)
说你写下my_exec
如下。
sub my_exec {
my($args,$stdout,$stderr) = @_; # caller untaints
open my $oldout, ">&STDOUT" or die "$0: save STDOUT: $!";
my $pid = open my $pipe, "-|" // die "$0: fork: $!";
if ($pid) {
if (defined $stderr) {
open STDERR, ">", $stderr or die "$0: open: $!";
}
while (<$pipe>) {
print STDERR scalar(localtime), ": ", $_;
}
close $pipe or die $! ? "$0: error closing $args->[0] pipe: $!"
: "$0: exit status " . ($? >> 8) . " from $args->[0]";
}
else {
open STDERR, ">&STDOUT" or die "$0: pipe STDERR: $!";
if (defined $stdout) {
open STDOUT, ">", $stdout or die "$0: open: $!";
}
else {
open STDOUT, ">&", $oldout or die "$0: restore STDOUT: $!";
}
exec @$args or die "$0: exec @$args: $!";
}
}
主要观点在documentation on open
:
如果您在命令
-
上打开管道(即,使用打开的单参数或双参数形式指定|-
或-|
),则隐式{{ 1}}已完成,因此open返回两次:在父进程中它返回子进程的pid,在子进程中它返回(已定义的)fork
。使用0
或defined($pid)
确定开放是否成功。
隐式//
的要点是在父进程和子进程之间建立管道。
文件句柄对父级的行为正常,但该文件句柄的I / O是从子进程的
fork
传送的。在子进程中,文件句柄未打开 - I / O从新的STDOUT
发生。
这几乎是完美的,除了你想要修改标准错误,而不是标准输出。
这意味着我们需要保存父级STDOUT
,以便孩子可以恢复它。这就是STDOUT
发生的事情。
将孩子(重定向)$oldout
复制到其STDOUT
上,安排基础守护程序的标准错误通过管道运行,父管读取,修改和输出。
一个稍微棘手的问题是处理重定向的位置。如果呼叫者想要重定向STDERR
,则需要在孩子身上发生。但是要重定向STDOUT
,父母需要这样做,因为这会让父母有机会修改流。
完整示例的代码具有以下形式。你提到了一个守护进程,所以我启用了Perl’s dataflow analysis known as taint mode。
STDERR
使用简单的#! /usr/bin/perl -T
use strict;
use warnings;
use v5.10.0; # for defined-or //
$ENV{PATH} = "/bin:/usr/bin";
sub my_exec {
# paste code above
}
#my_exec ["./mydaemon"];
#my_exec ["./mydaemon"], "my-stdout";
my_exec ["./mydaemon"], "my-stdout", "my-stderr";
mydaemon
输出转到单独的文件。
<强> 1。 #! /usr/bin/env perl
print "Hello world!\n";
warn "This is a warning.\n";
die "All done.\n";
强>
Hello world!
<强> 2。 my-stdout
强>
Tue Nov 5 17:58:20 2013: This is a warning. Tue Nov 5 17:58:20 2013: All done. ./wrapper: exit status 255 from ./mydaemon at ./wrapper line 23.
答案 1 :(得分:1)
fork
是如此之低。 IPC :: Open3是你应该使用的最小值。
use IPC::Open3 qw( open3 );
open(local *CHILD_STDIN, '<', '/dev/null') or die $!;
open(local *CHILD_STDOUT, '>', $stdout) or die $!;
my $pid = open3(
'<&CHILD_STDIN',
'>&CHILD_STDOUT',
\local *CHILD_STDERR,
$prog, @$args
);
open(my $stderr_fh, '>', $stderr) or die $!;
while (<CHILD_STDERR>) {
print $stderr_fh $ts . $_;
}
waitpid($pid, 0);