Date: Sun, 19 Apr 2020 17:12:42 +0900 From: Koichi Murase <myoga.mur...@gmail.com> Message-ID: <CAFLRLk-iJA+W0VifuzxwT=rthpmu+gaq-vnztsb8df0jga1...@mail.gmail.com>
| Currently, I do not see any rationale for the behavior (B) or (C). Before I make any other comments, I should point out that quite a bit of what is in the shell standard (and the rest of POSIX, and for that matter, many other standards) isn't there because there's a good reason for it, but just because the original shells implemented it that way, often for expediency purposes (the original Bourne shell had to run in the 64KB address space (code, data, and stack) of a PDP-11). So that's not really a meaningfull question to ask in this context, the standard might very well require something totally irrational, simply because that is how it has been implemented. If something is implemented a particular way, applications (scripts) may come to depend upon it, so changing it later can be difficult. All that aside, I agree that the wording in the standard is ambiguous. My first reading (my immediate impression) is that your interpretation A is what is intended, and only a return command executing directly from the trap action itself, and not one in a function that happens to be called, should be affected. (And of course, the former is only specified if the trap occurs while running a function or dot script). That is, with code like long_func() { t=$(trap -p) trap 'eval "$T"; return' INT while sleep 10 do printf . done } That is, it should not apply in functions called from a trap action, for them, return should act just like it would in a function called from any other source. Note that another intrepretation that you didn't list is that this magic return applies to return in functions called directly from the trap action string (which are more likely to be functions written expressly with the intent of being called this way) but not to functions called indirectly. Next thing to note is that all of this wording is to be changed in the next version of the standard - there's no longer any "exit status of the last command" stuff for return (or exit), rather these are to be specified to return the value of $? when no arg is given. When we do that, all we need to do is specify how traps affect $?, which should be (IMO), on entry, $? is the status of the last command (ie: starting a trap action changes nothing wrt $? - it holds the same value it would have had if there were no trap action called, and the next command simply started. On return from a trap action to the command that would have been executed next, had no trap action intervened, the exit status should be retained at the same value it had before the trap action was executed (the trap should not alter $?). If a trap action causes the control flow to be altered (that is, by executing a return/exit/break/continue outside of a context that is local to the trap action) then the exit status should be whatever the trap action causes to happen (that of the last command executed there). But that I believe this is the most appropriate specification does not mean that is what can go into the standard, that depends upon what the implementations actually do - and as there seems to be a diversity of implementations (including as to what is the command before the trap, when the trap is caused by a kill ... and possibly for async signals as well - some shells seem to use the status of the command before the kill command as the relevant one (that would be the status of the last command executed before the signal arrived), even though the standard is clear that the trap action cannot be run while a foreground command is running. Here the trap cannot run before the kill command starts (it is that which sends the signal) and assuming it is run in foreground, that means not until after the kill command completes, which means $? should be the status from he kill command. But some shells seem to run the trap action with $? being the status of the commane before the kill command (which would be the value of $? when the signal arrived). The end result, unless we can get agreement that some implementations are buggy, and will be fixed (which given the split seems an unlikely outcome) is likely to simply be that all of this simply becomes unspecified (or perhaps we could hope, implementation defined) which will mean even more cases where it becomes more difficult to write portable reliable code. kre