Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Prevent a bash script from terminating after handling a SIGINT

I am writing a bash wrapper for an application. This wrapper is responsible for changing the user, running the software and logging its output. I also want it to propagate the SIGINT signal.

Here is my code so far :

#!/bin/bash
set -e; set -u

function child_of {
    ps --ppid $1 -o "pid" --no-headers | head -n1
}

function handle_int {
    echo "Received SIGINT"
    kill -int $(child_of $SU_PID)
}

su myuser -p -c "bash /opt/loop.sh 2>&1 | tee -i >(logger -t mytag)" &
SU_PID=$!

trap "handle_int" SIGINT

wait $SU_PID
echo "This is the end."

My problem is that when I send a SIGINT to this wrapper, handle_int gets called but then the script is over, while I want it to continue to wait for $SU_PID.

Is there a way to catch the int signal, do something and then prevent the script from terminating ?

like image 903
mistyrouge Avatar asked Jul 08 '13 14:07

mistyrouge


People also ask

How do you prevent Ctrl C cause the termination of a running bash script?

How do I disable Control-C? You need to use the trap command which can enable or disable keyboard keys such as Crtl-C. SIGINT is Crtl-C and it is represented using number 2. Signal names are case insensitive and the SIG prefix is optional.

How do I stop a bash script execution?

If you are executing a Bash script in your terminal and need to stop it before it exits on its own, you can use the Ctrl + C combination on your keyboard.

What is sigint bash?

SIGINT is the signal sent when we press Ctrl+C. The default action is to terminate the process. However, some programs override this action and handle it differently. One common example is the bash interpreter.

What are the ways to get out of a bash loop inside of a script without exiting the actual script?

If you want to exit the loop instead of exiting the script, use a break command instead of an exit. #!/bin/bash while true do if [ `date +%H` -ge 17 ]; then break # exit loop fi echo keep running ~/bin/process_data done … run other commands here …


1 Answers

You have a gotcha: after Ctrl-C, "This is the end." is expected but it never comes because the script has exited prematurely. The reason is wait has (unexpectedly) returned non-zero while running under set -e.

According to "man bash":

If bash is waiting for a command to complete and receives a signal for which a trap has been set, the trap will not be executed until the command completes. When bash is waiting for an asynchronous command via the wait builtin, the reception of a signal for which a trap has been set will cause the wait builtin to return immediately with an exit status greater than 128, immediately after which the trap is executed.

You should wrap your wait call in set +e so that your program can continue running after handling a trapped signal while waiting for an asynchronous command.

Like this:

# wait function that handles trapped signal on asynchronous commands.
function safe_async_wait {
  set +e
  wait $1 # returns >128 on asynchronous commands
  set -e
}
#...
safe_async_wait $SU_PID
like image 84
jperville Avatar answered Oct 13 '22 18:10

jperville