$ perl -E 'say "y" while 1' | head -1
y
$ # cat.py
import sys
from signal import signal, SIGPIPE, SIG_DFL
signal(SIGPIPE,SIG_DFL)
for line in sys.stdin:
print(line)[0] https://docs.python.org/3/library/signal.html#note-on-sigpip...
Should be 141 instead of 1. Convention is that when a program dies because of a signal, the exit code should be 128 + the signal number, in this case 13. So, 128 + 13 = 141.
Here are some examples:
$ ( yes; >&2 echo $? ) | head -0
141
$ ( ping localhost; >&2 echo $? ) | head -0
141
$ ( perl -E 'say "y" while 1'; >&2 echo $? ) | head -0
141
In python, when using signal(SIGPIPE, SIG_DFL), you get the correct behaviour (at least regarding the exit status): $ ( python -c '
import sys
from signal import signal, SIGPIPE, SIG_DFL
signal(SIGPIPE,SIG_DFL)
while True: print("y");
' ; >&2 echo $? ) | head -0
141
> Do not set SIGPIPE’s disposition to SIG_DFL in order to avoid BrokenPipeError. Doing that would cause your program to exit unexpectedly also whenever any socket connection is interrupted while your program is still writing to it.Regarding that socket behavior, if that's the standard in other programming environments, why is it an issue from python's perspective? Doesn't seem worth eschewing standard unix conventions. I mean, it says "unexpectedly", but isn't it actually the expected behavior? Unexpected is for python to say that what's default (SIG_DFL) is unexpected.
signal.signal(signal.SIGPIPE, signal.SIG_DFL)
os.kill(os.getpid(), signal.SIGPIPE)
(Then there's no need to fiddle with stderr.) rm -vfr folder/ | head
involves SIGPIPE causing problems because it may or may not kill rm before it finishes deleting the directory, based on its internal output buffer size.Python provides mechanisms to handle signals. The point of a signal is to indicate something outside of your process has happened and you may want to respond to it. It's up to the program to respond to relevant signals and Python in no way stops a developer from doing that.
I don't follow your analogy. The default signal disposition for SIGPIPE is to silently terminate the process. Normally processes compose nicely on the command-line and this requires no extra work from the programmer. By disregarding this convention, most Python programs pollute your terminal when used in pipelines, which is why I claim that in this case Python is a bad unix citizen.
Python in no way stops you from a having a typical response to SIGPIPE, it's as simple as handling the exception and doing a sys.exit(), but it doesn't "just happen". This makes the typical path a little more contrived, but I don't think having explicit handling makes it a bad citizen.
To torture my analogy, in my mind a "bad citizen" of the highway may be a car incapable of doing the minimum speed limit, whereas Python just has a manual transmission vs Perl's automatic (in this case).
I'm splitting hairs though, your point is fair. I just think your objection is a little strong for what comes down to convenience.
How is this better? At least with the exception you can cleanly terminate your program if you need to.
Naturally, in the rare case you want to do some clean-up you can:
$ perl -E '$SIG{PIPE} = sub { die "cleanup" }; say "y" while 1' | head -1
y
cleanup at -e line 1.