ovk
ovk

Reputation: 2358

Multiple traps in the same bash process

I want to put couple of function into my .bashrc. The functions may execute for a long time so I'd like to be able to kill them with CTRL+C and print some information when this happens. I can capture CTRL+C by trapping SIGINT but I'm not sure what is the correct way to set different trap handlers for different functions inside the same script (.bashrc).

I came up with this solution which seems to work:

function foo()
{
    trap 'echo "foo() stopped"' SIGINT
    while true; do
        sleep 1
        echo "foo() working..."
    done
}

function bar()
{
    trap 'echo "bar() stopped"' SIGINT
    while true; do
        sleep 1
        echo "bar() working..."
    done
}

Example output:

$ foo
foo() working...
foo() working...
^Cfoo() stopped

$ bar
bar() working...
bar() working...
^Cbar() stopped

Now, my questions are:

  1. Am I understanding correctly that each time I do trap ... inside a function it resets signal handler for the whole bash session (process)? Or is it creating a new handler each time?
  2. Is this a good solution in general, or is there better solution to this problem?

Upvotes: 1

Views: 1588

Answers (1)

William Pursell
William Pursell

Reputation: 212634

Yes, the trap is resetting things globally. It would probably be good to reset it to its original value when the function ends. Something like:

foo() {
        old=$(trap -p SIGINT)
        trap 'echo "foo() stopped"' SIGINT
        ...
        eval set -- "$old"
        trap "$3" SIGINT
}

OTOH, it's probably more robust to run the function as a subshell, which would have the effect of only setting the trap for the subshell. Doing this is as simple as using ( and ) in the function definition:

foo()
(
    trap 'echo "foo() stopped"' SIGINT
    while true; do
        sleep 1
        echo "foo() working..."
    done
)

Upvotes: 4

Related Questions