Reputation: 60771
In perl, after fork()
ing I can redirect a child's stdout to a file like so
open STDOUT,">",$filename or die $!
I'm wondering if there is a way of "copying it", keeping the stdout on the parent's stdout but also copying to a specified file. It should happen in a way that would not require any buffering and the user would see the console output in real time. This would sort of be like the unix tee
. But ideally the solution would not involve any third party libraries.
Upvotes: 3
Views: 1933
Reputation: 29772
If the parent can wait around for the child to finish, the child could pipe its output back to the parent, which takes responsibility for printing it to both STDOUT and the destination file:
open my $destfile, '>', $path or die "Can't open destination file: $!\n";
my $pid = open my $child, '-|';
defined $pid or die "Can't fork: $!\n";
if ($pid == 0) {
# Child process:
print "I'm the child!\n";
close $destfile;
# do whatever
exit;
}
# Parent process:
while (<$child>) {
print STDOUT $_;
print $destfile $_;
}
close $child;
close $destfile;
Actually, even if the parent can't wait around for the child to finish, this strategy would still work if the parent first forked a child to perform the logic outlined above.
Upvotes: 0
Reputation: 139471
In the child, execute
open STDOUT, "|-", "tee", $output
or die "$0: failed to start tee: $!";
If you don't want to use tee
for some reason, you could use a poor man's version by forking another child via open STDOUT, "|-"
and doing the duplication in the grandchild:
#! /usr/bin/perl
use warnings;
use strict;
my $pid = fork;
die "$0: fork: $!" unless defined $pid;
if ($pid) {
waitpid $pid, 0;
}
else {
my $pid = open STDOUT, "|-";
die "$0: fork: $!" unless defined $pid;
select STDOUT; $| = 1; # disable STDOUT buffering
if ($pid) {
print "Hiya!\n";
system "echo Howdy";
close STDOUT or warn "$0: close: $!";
exit 0;
}
else {
open my $fh, ">", "/tmp/other-output" or die "$0: open: $!";
my $status;
while ($status = sysread STDIN, my $data, 8192) {
syswrite $fh, $data and print $data or die "$0: output failed: $!";
}
die "$0: sysread: $!" unless defined $status;
close $fh or warn "$0: close: $!";
exit 0;
}
}
Sample run:
$ ./owntee Hiya! Howdy $ cat other-output Hiya! Howdy
Upvotes: 3