Zsh Mailing List Archive
Messages sorted by: Reverse Date, Date, Thread, Author

Re: process substitution bug with set -e?

On Oct 14,  5:08pm, Vincent Lefevre wrote:
} Subject: Re: process substitution bug with set -e?
} On 2013-10-14 14:48:38 +0100, Peter Stephenson wrote:
} > On Mon, 14 Oct 2013 14:41:27 +0200
} > Vincent Lefevre <vincent@xxxxxxxxxx> wrote:
} > > #!/usr/bin/env zsh
} > > set -e
} > > { /bin/cp } 2>>(sleep 1; cat -n)
} > > 
} > > Due to /bin/cp failure and the "set -e", the parent shell exits
} > > immediately, without waiting for the extra processes:
} > > 
} > > Shouldn't the parent shell wait in this case?
} > 
} > It's not clear to me this is wrong, anyway (apart from the lack of
} > documentation).  You're in a non-interactive shell with no job control
} > (it's possible to mix job control with ERR_EXIT although it seems rather
} > unnatural).

I tried the above with "setopt MONITOR" and that doesn't have any effect;
ERR_EXIT always wins, and MONITOR isn't necessary if ERR_EXIT is not set,
even if the shell is not interactive.

By comparison, if that command is run with "zsh -c ..." instead of as a
script, zsh *never* waits for >>(...), regardless of other setopts.  This
seems to be a side-effect of the exec optimization which decides that,
because there are no further commands to execute after { /bin/cp }, the
parent can simply start that up and disappear.

That is,

    zsh -c '{ /bin/cp } 2>>(sleep 1; cat -n)'

always exits as soon as /bin/cp exits, whereas

    zsh -c '{ /bin/cp } 2>>(sleep 1; cat -n) ; :'

waits for "cat -n" so that it can execute ":" after it.  (Interestingly,
adding a TRAPZERR also induces -c to wait, I'm not sure why.)

} > you've got ERR_EXIT set you probably want to avoid tickling script bugs
} > when that's in operation.  I think it could be made to wait, but
} > there's a reasonable argument that as it's already detected the failure
} > and you've asked it to exit on failure it should just do that.
} I can see that it has the same behavior as, for instance:
}   { echo foo; exit } >>(sleep 1; cat -n)
} Again, one may wonder whether the shell should exit immediately.
} Is this clearly documented somewhere?

In general exiting from the shell either kills or disowns all jobs.  The
example of >>(process) is sort of a magic special case; it has to be run
asynchronously to be of any use, but "logically" it's part of the whole
job that is redirected to it, so when there is more to happen after it
zsh automatically does a "wait" for the implicitly backgrounded subshell.
That doesn't override the general rule about exiting.

Whether this is "clearly documented" ...

Incidentally exiting also bails out of "always" constructs without
executing the final block.

} If the expected behavior is to exit immediately with "exit" or due
} to a non-zero exit status with "set -e", then there should be a way
} to behave as if the closing } were reached (instead of exiting
} immediately). With EXIT and ZERR traps?

AFAICT this "there should be a way" isn't reflected in any other shell.
"TRAPEXIT() { wait }" almost works, but blocks the parent forever. (?)

Messages sorted by: Reverse Date, Date, Thread, Author