33

Is there possible in bash to call some command when function exits. I mean something like:

function foo
{
    # something like this maybe?
    trap "echo \"exit function foo\"" EXIT

    # do something
}

foo

And i want exit function foo to be printed out.

bercik
  • 816
  • 1
  • 9
  • 18
  • I needed this for a different context because my traps were leaking into my normal shell from bash_profile functions and I needed to catch and reset them before function termination. Regardless thankyou thankyou thankyou for asking this! – Scott Anderson Sep 07 '19 at 22:24

2 Answers2

44

Yes, you can trap RETURN :

$ function foo() {
>   trap "echo finished" RETURN
>   echo "doing some things"
> }
$ foo

Will display

doing some things
finished

From man bash's description of the trap builtin :

If a sigspec is RETURN, the command arg is executed each time a shell function or a script executed with the . or source builtins finishes executing.

Aaron
  • 24,009
  • 2
  • 33
  • 57
  • 1
    And can you trap also return code of this function? – bercik Aug 24 '17 at 12:54
  • 3
    No; you'll need to use a conditional like `if` or `case` if you want to take different actions based on the upcoming return code of the function. Note, too, that `trap` sets the handler globally, so any trap on `RETURN` that existed before `foo` was called is replaced once `foo` is called (given that the body of `foo` is a `{ ... }` command; `foo () ( trap ...; )` would not affect the calling context). – chepner Aug 24 '17 at 12:59
  • 1
    That said, you can trap `ERR` to fire on any non-zero return status *in addition to* the trap on `RETURN`. You just can't set different traps for a return code of 1 vs a return code of 2. – chepner Aug 24 '17 at 13:01
  • But can i somehow print error code in trap? Something like: `trap "echo \"error_code: $?\"" RETURN` – bercik Aug 24 '17 at 14:41
  • 1
    @bercik no, you can't. Even when using an implicit return, `$?` inside the trap command won't contain the success value of the last command executed in the scope of the function. If what you want is to trace the start/end and result of function executions there are other alternatives to traps though – Aaron Aug 24 '17 at 14:43
  • Can you tell more about this alternatives? I am working on logging component and I want to log when function exits and what was the result. But I want to have control wether this information should be logged or not. – bercik Aug 24 '17 at 14:46
  • @bercik I'm not so confident in my knowledge about them, it might be worth asking another question describing your functional need and explaining how you tried to implement it with traps. An obvious solution would be a wrapper function which takes a function name and arguments as parameters, log them, call the function, log and return the function success value and outputs. That would require using `eval` if I'm not mistaken, which is usually seen as bad practice. I believe there are other natives solutions, akin `bash -x` but less verbose / more targeted, but I can't remember any of them. – Aaron Aug 24 '17 at 15:24
  • Solution with wrapper seems not so bad. Maybe I will try it. Thanks – bercik Aug 25 '17 at 13:52
  • 1
    Use `EXIT` to call handler when not function but a script exits. – kyb Sep 02 '18 at 19:37
3

Concerning exiting with Ctrl+c (without declaring another function for exiting):

#!/bin/bash
function do_stuff() {
  function do_stuff_end() {
    # the code for exiting the function here
    echo "<the code for exiting the function here>"
    unset -f do_stuff_end
    trap "$trap_sigint" SIGINT
    return
  }
  trap_sigint="$(trap -p SIGINT)"
  trap "do_stuff_end; return" SIGINT
  # the code for the function here
  echo "<the code for the function here>"
  do_stuff_end
}

N.B.: the previous code is "just" working but needs improvement by considering the effects of other signals other than SIGINT

user37421
  • 407
  • 1
  • 5
  • 12