A piggy bank of commands, fixes, succinct reviews, some mini articles and technical opinions from a (mostly) Perl developer.

Jump to

Quick reference

Showing posts with label stderr. Show all posts
Showing posts with label stderr. Show all posts

STDERR and STDOUT appear in the wrong order when piping to a file

a Perl script - test.pl:

print "OUT 1\n";
print STDERR "ERR 2\n";
print "OUT 3\n";
print STDERR "ERR 4\n";
print "OUT 5\n";

Run the script, piping all output into a file:

perl test.pl &> file.log

cat file.log

ERR 2
ERR 4
OUT 1
OUT 3
OUT 5

Output is in the wrong order :(

Run it again using unbuffer:

unbuffer perl test.pl &> file.log

cat file.log

OUT 1
ERR 2
OUT 3
ERR 4
OUT 5

Output is in the correct order :)

(source)

Another way:

script -c 'perl ~/temp/stream.pl' file.log

cat file.log

(source)

Run an external command from Perl, capturing both the output and the exit value


# This is how to run an external command from Perl,
# capturing both the output and the exit value

sub run_external_command {
    my ($self, $command) = @_;
    $self->logger->debug("Running command: $command");

    my $output = '';
    $command .= ' 2>&1 | '; # capture all output
    open(my $capture, $command);
    {
        local $/ = undef;
        $output = <$capture>;
    }
    close($capture);
    chomp($output);

    my $exit_value = ${^CHILD_ERROR_NATIVE} >> 8;
    $self->logger->debug("Exit value of command: '$exit_value'");
    $self->logger->debug("Output of command: '".($output || '[no output]')."'");

    return ($exit_value, $output);
}

This is another way:

use IPC::Open3;

sub run_external_command_2 {
  local (*my_in, *my_out, *my_err);

  my $command = "some command here that might error";
  my $pid = open3(\*my_in, \*my_out, \*my_err, $command) or die($!);

  close(my_in);
  my $std_out = do { local $/; };close(my_out);
  my $std_err = do { local $/; };close(my_err);

  waitpid($pid, 0);
  my $exit_code = $? >> 8;

  return { exit_code => $exit_code, std_out => $std_out, std_err => $std_err };
}