Consider this Python script:
for i in range(4000):
print(i)
and this Perl script:
for my $i (0..4000-1) {
print $i, "\n";
}
python3 pipe.py | head -n3000 >/dev/null
produces an error:
Exception ignored in: <_io.TextIOWrapper name='<stdout>' mode='w' encoding='UTF-8'>
BrokenPipeError: [Errno 32] Broken pipe
but
perl pipe.pl | head -n3000 >/dev/null
produces no error (in Perl v5.26.1).
Why such a discrepancy between Python and Perl? How to make Perl to produce a similar error message?
What's going on here is that in both cases you have a process writing to a pipe whose read end was closed (by head
exiting after a certain number of bytes).
This causes a SIGPIPE
signal to be sent to the writing process. By default this kills the process. The process can ignore the signal if it wants to, which just makes the write
call fail with an EPIPE
error.
Starting with version 3.3, Python raises a BrokenPipeError
exception in this case, so it looks like Python 1) ignores SIGPIPE
by default and 2) translates EPIPE
to a BrokenPipeError
exception.
Perl does not ignore or handle signals by default. That means it gets killed by SIGPIPE
in your example, but because it is not the last command in a pipeline (that would be head
here), the shell just ignores it. You can make it more visible by not using a pipeline:
perl pipe.pl > >(head -n3000 >/dev/null)
This piece of bash trickery makes perl write to a pipe, but not as part of a shell pipeline. I can't test it now, but at minimum this will set $?
(the command exit status) to 141
in the shell (128 + signal number, which for SIGPIPE
is 13), and it may also report a Broken pipe
.
You can deal with it manually in the Perl code, though:
Variant 1: Throw an error from the signal handler
$SIG{PIPE} = sub { die "BrokenPipeError" };
Variant 2: Ignore the signal, handle write errors
$SIG{PIPE} = 'IGNORE';
...
print $i, "\n" or die "Can't print: $!";
Note that in this case you have to think about buffering, however. If you don't enable autoflush (as in STDOUT->autoflush(1)
) and output is going to a pipe or file, Perl will collect the text in an internal buffer first (and the print
call will succeed). Only when the buffer gets full (or when the filehandle is closed, whichever happens first) is the text actually written out and the buffer emptied. This is why close
can also report write errors.