help-bash
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [Help-bash] When pipes fail (and when not)


From: Chet Ramey
Subject: Re: [Help-bash] When pipes fail (and when not)
Date: Wed, 28 Nov 2018 14:10:57 -0800
User-agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.14; rv:52.0) Gecko/20100101 Thunderbird/52.9.1

On 11/28/18 1:16 PM, Bob Proulx wrote:
> Chet Ramey wrote:
>> Paul Wagner wrote:
>>> 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.
> 
> Using echo as in the above is the bash builtin echo which doesn't
> print diagnostics.  

Clearly it's not true that the builtin echo doesn't print diagnostics. If
the SIGPIPE doesn't cause the shell to exit (it's a fatal error) the
builtin echo will print a write error message.

>> Each element of a pipeline is executed in a subshell environment, described
>> in
>>
>> http://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#tag_18_12
>>
>> "A subshell environment shall be created as a duplicate of the shell
>> environment, except that signal traps that are not being ignored shall be
>> set to the default action. [...] Additionally, each command of a multi-
>> command pipeline is in a subshell environment; as an extension, however,
>> any or all commands in a pipeline may be executed in the current
>> environment."
> 
> As I read that it appears to give a solution.  It says that if a
> signal is not being ignored then it will be set back to the default.
> Therefore if we set a SIGPIPE handler to anything trivial but not
> ignore and not default then that would make it not be ignored and
> therefore should be set back to the default SIG_DFL.  But that does
> not seem to be true.

Yes, it's exactly what happens. If you catch SIGPIPE with a trap in the
parent shell, the SIGPIPE disposition is set to SIG_DFL in the subshell
begun to execute the first pipeline element. If you don't trap it, that
subshell exits when it gets the SIGPIPE thrown by the write on a broken
pipe. That's why this script doesn't print any "foo"s and exits right
after dd prints its messages.

trap 'echo foo >&2' pipe
for i in {0..9}; do echo $i; sleep 1; done | dd bs=1 count=10


The only instance in which this will not happen is when SIGPIPE is set
to SIG_IGN before the parent shell executes. A subshell doesn't count as
"when the shell starts;" POSIX determined that via an interpretation.
Bash used to consider the subshell a "shell starting," but changed to
match the interpretation a while back (I didn't check exactly when, but
I use bash-4.4 for all my examples).

> 
>> Subshell environments don't inherit traps from the parent shell, unless
>> the trap has specified that the signal is to be ignored. Bash always
>> executes the first element of a pipeline in a subshell environment.
>>
>> If you define the trap in the same subshell environment as the for loop,
>> you'll get the output you want.
> 
>   trap 'echo foo 1>&2' PIPE  # set a PIPE handler so it is not ignored
> 
> But I can't create any example which provides for resetting SIGPIPE
> handling back to the original SIG_DFL in a child of a process where
> the parent had previously ignored it.  I recall this always having
> been the case forever for shells.

Yes, exactly. If the shell starts up with a signal set to SIG_IGN, you
can't do anything with it. The shell doesn't have to tell you you can't,
either. If the shell itself sets the signal to be ignored via trap, you
can use another trap to change the disposition.

You can show this by running the following:

trap '' SIGPIPE
{ trap 'echo foo >&2' pipe ; for i in {0..9}; do echo $i; sleep 1; done; }
| dd bs=1 count=10

If you run that script, you'll get five "foo"s and five write error
messages.

If you run this script:

trap '' SIGPIPE
{ for i in {0..9}; do echo $i; sleep 1; done; } | dd bs=1 count=10

you'll get five error messages because the subshell inherited the
SIG_IGN.

> Perhaps in the above the "traps that are not being ignored shall be
> set to the default action" really means set back to the previous
> action?  Where the previous action was that it was ignored?

What? A signal can have three possible dispositions: SIG_DFL, SIG_IGN,
and an application signal handler. Signals that are ignored when the
shell starts are unmodifiable. Signals that are set to SIG_IGN by the
shell via a trap stay ignored in the subshell, but the subshell can
modify them, as shown above. Signals that are not ignored are either
SIG_DFL or trapped. In that case, the subshell sets them to SIG_DFL when
it is forked, but can set traps to modify their disposition.

Chet
-- 
``The lyf so short, the craft so long to lerne.'' - Chaucer
                 ``Ars longa, vita brevis'' - Hippocrates
Chet Ramey, UTech, CWRU    address@hidden    http://tiswww.cwru.edu/~chet/



reply via email to

[Prev in Thread] Current Thread [Next in Thread]