Perl, перенаправить стандартный вывод, но оставить на родительском - PullRequest
3 голосов
/ 19 июля 2010

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

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

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

Ответы [ 2 ]

3 голосов
/ 20 июля 2010

Для ребенка выполните

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
0 голосов
/ 20 июля 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;

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

...