http://www.perlmonks.org?node_id=979163

apomatix has asked for the wisdom of the Perl Monks concerning the following question:

I want to get both the output and status of a pipe. Here is a working example:

#!/usr/bin/perl use strict; open my $fh, '-|', 'bash -c "echo Hello; exit 1"'; print <$fh>; close $fh; my $status = $? >> 8; print "$status\n";

Fine. It outputs

Hello 1

Now let's try to use autodie:

#!/usr/bin/perl use strict; use autodie; open my $fh, '-|', 'bash -c "echo Hello; exit 1"'; print <$fh>; close $fh; my $status = $? >> 8; print "$status\n";

No good, that breaks it:

Hello Can't close(GLOB(0x10082a098)) filehandle: '' at test.pl line 7

It is the "close" statement. So we can take that out.

use strict; use autodie; open my $fh, '-|', 'bash -c "echo Hello; exit 1"'; print <$fh>; #close $fh; my $status = $? >> 8; print "$status\n";

Now it is broken differently---it has lost the exit status:

Hello 0

I need to call close in order to get the exit status of a pipe.

So now I have settled on this ugly thing:

use strict; use autodie; open my $fh, '-|', 'bash -c "echo Hello; exit 1"'; print <$fh>; {no autodie; close $fh;} my $status = $? >> 8; print "$status\n";

That seems to work, but I'm not doing any error checking on the close statement:

Hello 1
Can I use close with autodie when my pipe fails? If not, how should I check for errors?

Replies are listed 'Best First'.
Re: close and autodie on pipes
by runrig (Abbot) on Jun 29, 2012 at 19:55 UTC
    If you want to catch exceptions, use eval:
    my $result = eval { close $fh }; unless ($result) { print "Got an error: $@\n"; }
    Or even:
    my $result = eval { open my $fh, '-|', 'bash -c "echo Hello; exit 1"'; print for <$fh>; close $fh; }; ...
Re: close and autodie on pipes
by Athanasius (Archbishop) on Jun 30, 2012 at 03:12 UTC

    From close in perldoc (emphasis added):

    If the filehandle came from a piped open, close returns false if one of the other syscalls involved fails or if its program exits with non-zero status. If the only problem was that the program exited non-zero, $! will be set to 0.

    So, by setting your pipe program to exit 1 you are ensuring that close() fails (i.e., returns false). autodie is working correctly here.

    how should I check for errors?
    #! perl use strict; use warnings; use autodie; open(my $fh, '-|', 'bash -c "echo Hello; exit 1"'); print <$fh>; { no autodie; unless (close($fh)) { die "Real pipe error: $!" if $!; } } print "status: ", ($? >> 8), "\n";

    HTH,

    Athanasius <°(((><contra mundum