Perl, перенаправить стандартный вывод, но сохранить родителя

В perl после fork()ing я могу перенаправить дочерний стандартный вывод в такой файл

open STDOUT,">",$filename or die $!

Мне интересно, есть ли способ «копировать его», сохраняя стандартный вывод на родительском стандартном выводе, но также копируя в указанный файл. Это должно происходить таким образом, чтобы не требовалось никакой буферизации, и пользователь мог видеть вывод консоли в режиме реального времени. Это было бы похоже на unix tee. Но в идеале решение не должно включать сторонние библиотеки.


person Mike    schedule 19.07.2010    source источник
comment
Вы упомянули, что в идеале решение не должно включать сторонние библиотеки, но ради потомства IO::Tee был написан именно для решения этой проблемы и справляется с этим очень хорошо.   -  person cikkle    schedule 19.07.2010
comment
Я бы предположил, что должен быть простой способ сделать это, используя сборку в файле io   -  person Mike    schedule 19.07.2010


Ответы (2)


В дочернем выполнить

open STDOUT, "|-", "tee", $output
  or die "$0: failed to start tee: $!";

Если вы по какой-то причине не хотите использовать tee, вы можете использовать версию для бедняков, разветвив другой дочерний элемент через open STDOUT, "|-" и выполнив дублирование во внуке:

#! /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;
  }
}

Пример запуска:

$ ./owntee 
Hiya!
Howdy

$ cat other-output 
Hiya!
Howdy
person Greg Bacon    schedule 19.07.2010

Если родитель может дождаться завершения дочернего процесса, дочерний элемент может передать свой вывод обратно родителю, который берет на себя ответственность за его печать как в STDOUT, так и в файл назначения:

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;

На самом деле, даже если родитель не может дождаться завершения дочернего процесса, эта стратегия все равно будет работать, если родитель сначала разветвит дочерний процесс для выполнения описанной выше логики.

person Sean    schedule 19.07.2010