mainThe GNU Bourne-Again SHell - Support: sr #110223, trap ERR (or set -e) didn't work...

 
 

sr #110223: trap ERR (or set -e) didn't work inside functions and subshells

Submitter:  None
Submitted:  Fri 17 Apr 2020 09:47:20 PM UTC
   
 
Category:  None Priority:  5 - Normal
Severity:  4 - Important Status:  Invalid
Privacy:  Public Assigned to:  None
Originator Email:  -email is unavailable- Open/Closed:  Open
Operating System:  GNU/Linux
* Mandatory Fields

Add a New Comment Rich Markup
   

Jump to the original submission

Fri 04 Sep 2020 06:39:52 AM UTC, comment #7: 

I have raised SR 110302 (https://savannah.gnu.org/support/?110302) as a feature request for the err_return option.

Timothy Barbour <trb>
Thu 03 Sep 2020 06:11:41 AM UTC, comment #6: 

I think the fundamental problem here could be overcome by implementing the err_return option from zsh. When a function fails partway through, err_return causes the function to return early, rather than exiting.

There is definitely a problem with the current behaviour (despite being compliant with POSIX). I really dislike the fact that bash ignores err_exit inside a function called from a conditional. Sometimes this can be avoided (clumsily) by calling the function directly, then testing the function return status via $?, but there are other cases (e.g. when the function is called via the time builtin) where this solution will not work. I have one of these cases.

err_return would solve this problem, and would not break POSIX compliance, because it would be off by default.

Timothy Barbour <trb>
Wed 22 Apr 2020 06:23:36 PM UTC, comment #5: 


> Follow-up Comment #4, sr #110223 (project bash):
>
>
> комментарий №3:
>>
>> It's a case of mismatched expectations. `set -e' isn't as useful as you
>> hope it will be.
>
> Well, very bad, because there aren't any reasons not to make it (or some
> additional to it) useful, just strange design issue. Very bad and important
> issue, because `set -e` functionality can be very useful, but now is very
> dangerous and so - should never be used anywhere to avoid problems.

`set -e' works the way it does for historical reasons, and is standardized
to work that way. Users expect it to work as it does now. If it's not
appropriate for what you want to do, well, you're not the first person to
feel that way.

>
> I'm absolutely sure that manpage must be corrected to explicitly specify that
> state of disabling trap ERR is inherited to all execution levels, can not be
> overrided, and so, trap ERR usage in subshells and functions are very
> dangerous and very limited. Because if you don't know bash on professional
> level (as most bash users) - you willn't understand it by current man.

The description of the ERR trap states explicitly that it runs in exactly
the same contexts where `set -e' would exit the shell. If you want different language for `set -e', propose something a little more detailed
than the above. The POSIX rationale text even warns against trying to use
`set -e' in shell functions, if you were thinking of looking at that.


> Moreover. `set -E` and `trap ERR`, as I understand, are not a POSIX standad
> and I do not see any reasons not to make them working normally.

`set -E' is not relevant here. ERR traps are inherited by functions and
other execution environments according to their rules, and they trigger
whenever `set -e' would, as I said, exit the shell. I don't see any
reason to change that.
 >

> So, I think that bash shoud have a "Feature request" bug. At least, bash
> should correct manpage.

Please suggest some sample language you'd like to see added to the `set -e'
description.


> Then - bash can implement some replace of POSIX `set
> -e`, that will not inherite disabled state, and should switch trap ERR to that
> behavior too (at least allow to force enabled state by trap ERR inside
> functions etc). It's a super easy task - just reset global variable on each
> fork and each function call.

The first suggestion has come up before, but nobody has ever been able to
propose a rigorous enough specification to make it work in any useful way.
I don't see a reason to change the behavior of the ERR trap after 20
years.


Chet Ramey <chet>
Group administrator
Wed 22 Apr 2020 01:55:11 PM UTC, comment #4: 


комментарий №3:

>
> It's a case of mismatched expectations. `set -e' isn't as useful as you
> hope it will be.


Well, very bad, because there aren't any reasons not to make it (or some additional to it) useful, just strange design issue. Very bad and important issue, because `set -e` functionality can be very useful, but now is very dangerous and so - should never be used anywhere to avoid problems.

I'm absolutely sure that manpage must be corrected to explicitly specify that state of disabling trap ERR is inherited to all execution levels, can not be overrided, and so, trap ERR usage in subshells and functions are very dangerous and very limited. Because if you don't know bash on professional level (as most bash users) - you willn't understand it by current man.

Moreover. `set -E` and `trap ERR`, as I understand, are not a POSIX standad and I do not see any reasons not to make them working normally.

So, I think that bash shoud have a "Feature request" bug. At least, bash should correct manpage. Then - bash can implement some replace of POSIX `set -e`, that will not inherite disabled state, and should switch trap ERR to that behavior too (at least allow to force enabled state by trap ERR inside functions etc). It's a super easy task - just reset global variable on each fork and each function call.

Why not to allow users use trap ERR in their scripts as it should  be used? So script (or any subshell) must generate ERR on every non-catched error, no matter where it is (in function, in subshell etc). It's very good feature, moreover, as I understand, it's already implemented, but disabled for compatibility with POSIX `set -e`. Currently, all features related to ERR are almost useless, but it's very easy to make them useful.

The fact that bash have error handling functionality, but it is broken (for any programmer, who want to use it) for some strange reasons (no matter that are written in POSIX or internally implemented - you always can add new flag, it's a bash, not ash or similar) - it is certanly an important bug. Hope that it will be fixed, because it's very hard to write complex big scripts without working trap ERR (|| catch_err on every line - it's a more or less working solution, but very strange solution)

Anonymous
Tue 21 Apr 2020 03:40:41 PM UTC, comment #3: 


> comment #1:
>> `set -e' (and consequently the ERR trap) is not in effect when the command
> is on the left side of an AND-OR list.
>>
>> There are other situations where set -e is ineffective; there is a full list
> in the man page.
>>
>
> Man page:
>
> The ERR trap is not executed if the failed command is part of the command list
> immediately following a while or until keyword, part of the test in an if
> statement, part of a command executed in a && or || list except the command
> following the final && or ||, any command in a pipeline but the last, or if
> the command's return value is being inverted using !. These are the same
> conditions obeyed by the errexit (-e) option.
>
> echo 12>/SOME/NONEXISTING/FILE is not a part of anything from this list.


It is. It's part of a shell function that is executed on the left side of
an OR list. The shell knows it's executing the command substitution as
part of the OR list, so it ignores the errexit setting, and the child
process inherits that state. This is how shells work, and how POSIX
specifies them to behave.

There are a lot of threads on bug-bash and help-bash that discuss this.
Here are several from the last few years:

https://lists.gnu.org/archive/html/bug-bash/2019-11/msg00048.html
https://lists.gnu.org/archive/html/help-bash/2018-12/msg00036.html
https://lists.gnu.org/archive/html/help-bash/2018-03/msg00007.html
https://lists.gnu.org/archive/html/bug-bash/2018-06/msg00034.html
https://lists.gnu.org/archive/html/help-bash/2016-07/msg00000.html
https://lists.gnu.org/archive/html/bug-bash/2015-08/msg00062.html



Call

> of function is a part, not the commands inside. Logically it's absolutely
> different things. It's even another process!


That's not the case, no matter how much you want it to be. The `commands
inside' a function are part of the commands executed on the left side of
the OR list.

There's no reason to expect a subshell, even though it's a separate
process, to discard the parent's state. It's an exact copy of the
parent shell.

Moreover, from topic about set:

>
> -E      If set, any trap on ERR is inherited by shell functions, command
> substitutions, and commands executed  in  a  subshell  environment.
>
> No, this flag will never work in real cases! Please, at least add comments
> about set -e, trap ERR and set -E to manpage and clarify that this
> functionality can't be used with functions, subshells and sourced files if you
> want to check result code from it.


The ERR trap is executed under exactly the same conditions as `set -e'
would exit the shell. The trap is inherited, but since `set -e' has no
effect, it's not run.

>
> Current manpage tells that set -e should kill my subshell inside function and
> that you can use set -E to export traps always (but you can't in general
> case)


No, it doesn't. You are executing the command as part of an OR list, so the
errexit setting has no effect (in fact, you can't even turn it on).

>
> But. Currently there are no way to check errors inside functions. I really
> don't understand why bash do not work as expected and as it's written in man.


It's a case of mismatched expectations. `set -e' isn't as useful as you
hope it will be.

Chet Ramey <chet>
Group administrator
Tue 21 Apr 2020 12:46:04 AM UTC, comment #2: 

comment #1:

> `set -e' (and consequently the ERR trap) is not in effect when the command is on the left side of an AND-OR list.
>
> There are other situations where set -e is ineffective; there is a full list in the man page.
>


comment #1:

> `set -e' (and consequently the ERR trap) is not in effect when the command is on the left side of an AND-OR list.
>
> There are other situations where set -e is ineffective; there is a full list in the man page.
>


Man page:

The ERR trap is not executed if the failed command is part of the command list immediately following a while or until keyword, part of the test in an if statement, part of a command executed in a && or || list except the command following the final && or ||, any command in a pipeline but the last, or if the command's return value is being inverted using !. These are the same conditions obeyed by the errexit (-e) option.

echo 12>/SOME/NONEXISTING/FILE is not a part of anything from this list. Call of function is a part, not the commands inside. Logically it's absolutely different things. It's even another process! Moreover, from topic about set:

-E      If set, any trap on ERR is inherited by shell functions, command substitutions, and commands executed  in  a  subshell  environment.

No, this flag will never work in real cases! Please, at least add comments about set -e, trap ERR and set -E to manpage and clarify that this functionality can't be used with functions, subshells and sourced files if you want to check result code from it.

Current manpage tells that set -e should kill my subshell inside function and that you can use set -E to export traps always (but you can't in general case)

But. Currently there are no way to check errors inside functions. I really don't understand why bash do not work as expected and as it's written in man. Bash should disable ERR only on current code level, and do not in calling functions. Without it set -e can't be used.

Anonymous
Mon 20 Apr 2020 04:10:15 PM UTC, comment #1: 

`set -e' (and consequently the ERR trap) is not in effect when the command is on the left side of an AND-OR list.

There are other situations where set -e is ineffective; there is a full list in the man page.

Chet Ramey <chet>
Group administrator
Fri 17 Apr 2020 09:47:20 PM UTC, original submission:  

I'm trying to use trap ERR inside my scripts and suddenly realise that it doesn't work at all in most cases, because I split my scripts to functions and libraries.

Test case:

function hmmm() {
    trap 'exit 10' ERR
    echo 12>/SOME/NONEXISTING/FILE
    # some commands that must not be done ever if previous has failed
    echo "THAT MUST NOT BE PRINTED" >&2
    return 5
}  

echo ok1
a=$(hmmm) || status="$?"
echo "function returns: $status"

What I expect to see:

ok1
test2.sh: line 3: /SOME/NONEXISTING/FILE: No such file or directory
function returns: 10

But I see:
ok1
test2.sh: line 3: /SOME/NONEXISTING/FILE: No such file or directory
THAT MUST NOT BE PRINTED
function returns: 5

So set -e absolutely unusefull in functions (because you can't use it with returning something), and, that also important, in libraries, which should be sourced with 'source "mylib.sh" || exit 1' (everyone always add '|| exit 1' or smth similar after source, so 'set -e' will never works inside libraries).

Moreover, as I understand, there aren't any working method to enable trap ERR inside subshells, functions and libraries.

This bug is very important because you can accidentally disable errors trapping inside some third-party libraries or functions easily and willn't ever know about it till this library will do rm -rf /.

Constructions 'somecode || true' must always disable errors only on current execution level, not inside called functions or other types of code.

GNU bash, version 4.4.12(1)-release (x86_64-pc-linux-gnu)

Anonymous

 

(Note: upload size limit is set to 16384 kB, after insertion of the required escape characters.)

Attach Files:
   
   
Comment:
   

No files currently attached

 

Depends on the following items: None found

Items that depend on this one: None found

 

Carbon-Copy List
  • -email is unavailable- added by trb (Posted a comment)
  • -email is unavailable- added by chet (Posted a comment)
  • -email is unavailable- added by None (Submitted the item)
  •  

    There are 0 votes so far. Votes easily highlight which items people would like to see resolved in priority, independently of the priority of the item set by tracker managers.

    Only logged-in users can vote.

     

    Follows 1 latest change.

    Date Changed by Updated Field Previous Value => Replaced by
    2020-04-20 chet StatusNone Invalid

    Back to the top

    Powered by Savane 3.13-4448.
    Corresponding source code