[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: [Help-bash] When pipes fail (and when not)
From: |
Eric Blake |
Subject: |
Re: [Help-bash] When pipes fail (and when not) |
Date: |
Wed, 28 Nov 2018 09:45:56 -0600 |
User-agent: |
Mozilla/5.0 (X11; Linux x86_64; rv:60.0) Gecko/20100101 Thunderbird/60.3.0 |
On 11/28/18 9:02 AM, Paul Wagner wrote:
On 28.11.2018 13:54, Eric Blake wrote:
I still don't understand why setting the trap on a system that has
SIGPIPE vital doesn't work, so I'd be very greatful for any hints.
It's a lame restriction from POSIX based on historical practice (that
I _really_ wish we weren't stuck with):
http://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#trap
"Signals that were ignored on entry to a non-interactive shell cannot
be trapped or reset, although no error need be reported when
attempting to do so. An interactive shell may reset or catch signals
ignored on entry. Traps shall remain in place for a given shell until
explicitly changed with another trap command."
Maybe I don't get your point, but I think there might be a
missunderstanding: In my previous post I was referring to my example on
Linux, where SIGPIPE is not ignored by default:
Okay, there was indeed some misunderstanding. My quote was about the
situation where a bash script starts with sigpipe inherited as ignored -
there is NOTHING the script can do to undo that, short of re-execing via
an intermediary non-shell process that can lift the sigpipe ignored
inheritance before going back into shell. (And that's the situation
that most frequently plagues CI test setups, if they leak an ignored
sigpipe into child processes under test). The fact that POSIX forbids
the shell from undoing an inherited ignored sigpipe is rather awkward,
but we are stuck with it.
Now, on to your complaint - when does the trap handler for sigpipe
actually fire. Well, that depends on whether bash started with sigpipe
ignored - because if it did, you cannot undo that effect short of
re-execing.
for i in {0..9}; do echo $i; sleep 1; done | dd bs=1 count=10
ends as expected after 5 iterations, so SIGPIPE is not ignored in the
current shell;
I'm running tests with an interactive environment where I _know_ that
sigpipe is not ignored from the outside. Note, however, that the
subsidiary bash takes a full 10 seconds to complete, regardless of
whether sigpipe is inherited ignored or default:
$ time (trap '' pipe; bash -c 'for i in {0..9}; do /bin/echo $i; sleep
1; done | dd bs=1 count=10')
0
1
2
3
4
10+0 records in
10+0 records out
10 bytes copied, 4.00699 s, 0.0 kB/s
/bin/echo: write error: Broken pipe
/bin/echo: write error: Broken pipe
/bin/echo: write error: Broken pipe
/bin/echo: write error: Broken pipe
/bin/echo: write error: Broken pipe
real 0m10.033s
user 0m0.026s
sys 0m0.007s
$ time (trap - pipe; bash -c 'for i in {0..9}; do /bin/echo $i; sleep 1;
done | dd bs=1 count=10')
0
1
2
3
4
10+0 records in
10+0 records out
10 bytes copied, 4.0058 s, 0.0 kB/s
real 0m10.027s
user 0m0.016s
sys 0m0.012s
So, even when sigpipe is not ignored, and even though the output stops
after 5 seconds, the subshell takes the full ten seconds to complete
execution because I have not actually stopped the loop, but merely
changed what happens with the /bin/echo processes outputting to a pipe
that no longer has a reading process.
But, when bash starts with sigpipe ignored, I cannot undo that from
within bash:
$ time (trap '' pipe; bash -c 'trap - pipe; for i in {0..9}; do
/bin/echo $i; sleep 1; done | dd bs=1 count=10')
0
1
2
3
4
10+0 records in
10+0 records out
10 bytes copied, 4.00624 s, 0.0 kB/s
/bin/echo: write error: Broken pipe
/bin/echo: write error: Broken pipe
/bin/echo: write error: Broken pipe
/bin/echo: write error: Broken pipe
/bin/echo: write error: Broken pipe
real 0m10.029s
user 0m0.016s
sys 0m0.014s
So, the fact that you were able to install a trap handler that made a
difference shows that you are, indeed, in an environment where you did
not inherit an ignored sigpipe.
trap '' pipe
for i in {0..9}; do echo $i; sleep 1; done | dd bs=1 count=10
reports a write error five times after the fifth iteration, as expected;
but installing another trap like
trap 'echo foo >&2' pipe
for i in {0..9}; do echo $i; sleep 1; done | dd bs=1 count=10
ends after 5 iterations (so SIGPIPE is not trapped, but handled again),
but does not write 'foo' to stderr (the terminal), and I don't
understand why.
The other consideration is to figure out WHEN the trap handler fires.
It does NOT fire every time that /bin/echo dies due to SIGPIPE, but ONLY
if the entire pipeline dies due to SIGPIPE. But 'dd' did not die due to
SIGPIPE, therefore the trap handler never fires.
The fact that you have installed a trap handler at all determines
whether bash lets /bin/echo inherit sigpipe ignored or defaulted, and
therefore determines whether /bin/echo outputs an error message; but
since the trap handler is NOT firing (because the pipeline itself is not
dying due to SIGPIPE, which would only happen if 'dd' exited that way),
the loop is executing all ten /bin/echo processes, whether or not the dd
process is still around to consume them, and without your handler ever
firing.
--
Eric Blake, Principal Software Engineer
Red Hat, Inc. +1-919-301-3266
Virtualization: qemu.org | libvirt.org
- [Help-bash] When pipes fail (and when not), Paul-Jürgen Wagner, 2018/11/05
- Re: [Help-bash] When pipes fail (and when not), Bob Proulx, 2018/11/24
- Re: [Help-bash] When pipes fail (and when not), Paul Wagner, 2018/11/27
- Re: [Help-bash] When pipes fail (and when not), Chet Ramey, 2018/11/27
- Re: [Help-bash] When pipes fail (and when not), Paul Wagner, 2018/11/28
- Re: [Help-bash] When pipes fail (and when not), Eric Blake, 2018/11/28
- Re: [Help-bash] When pipes fail (and when not), Paul Wagner, 2018/11/28
- Re: [Help-bash] When pipes fail (and when not),
Eric Blake <=
- Re: [Help-bash] When pipes fail (and when not), Paul Wagner, 2018/11/28
- Re: [Help-bash] When pipes fail (and when not), Chet Ramey, 2018/11/28
- Re: [Help-bash] When pipes fail (and when not), Bob Proulx, 2018/11/28
- Re: [Help-bash] When pipes fail (and when not), Chet Ramey, 2018/11/28