darwin schuppan
darwin schuppan

Reputation: 33

How can I send a signal without the shell waiting for the currently running program to finish?

If I send a signal using kill, it seems to wait until the current program (in this example sleep 1000) finishes running. When I instead send SIGINT via pressing Ctrl+C in the shell, it receives the interrupt immediately however.

What I want, however, is for the interrupt to be received immediately after sending the signal via kill. Also, why does it behave like I would want it to when I press Ctrl+C?

#!/usr/bin/env sh
int_after_a_while() {
    local pid=$1
    sleep 2
    echo "Attempting to kill $pid with SIGINT"
    # Here I want to kill the process immediately, but it waits until sleep finishes
    kill -s INT $pid
}

trap "echo Interrupt received!" INT
int_after_a_while $$ &
sleep 1000

I would appreciate any help on this issue. Thanks in advance!

Upvotes: 1

Views: 613

Answers (1)

jilles
jilles

Reputation: 11232

As noted in the referenced answer https://unix.stackexchange.com/questions/282525/why-did-my-trap-not-trigger/282631#282631 the shell will normally wait for a utility to complete before running a trap. Some alternatives are:

  • Start the long running process in the background, then wait for it using the wait builtin. When a trapped signal is received during such a wait, the wait is interrupted and the trap is taken. Unfortunately, the exit status of wait does not distinguish between the child process exiting on a signal and a trap occurring. For example
    sleep 1000 &
    p=$!
    wait "$p"
  • Send a signal to the whole process group via kill -s INT 0. The effect is much like if the user had pressed Ctrl+C, but may be more extreme than you want if your script is run from another script.
  • Use a shell such as zsh or FreeBSD sh that supports set -o trapsasync which allows running traps while waiting for a foreground job.

Upvotes: 2

Related Questions