Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Terminate running commands when shell script is killed [duplicate]

Tags:

bash

For testing purposes I have this shell script

#!/bin/bash
echo $$
find / >/dev/null 2>&1

Running this from an interactive terminal, ctrl+c will terminate bash, and the find command.

$ ./test-k.sh
13227
<Ctrl+C>
$ ps -ef |grep find
$

Running it in the background, and killing the shell only will orphan the commands running in the script.

$ ./test-k.sh &
[1] 13231
13231
$ kill 13231
$ ps -ef |grep find
nos 13232     1  3 17:09 pts/5    00:00:00 find /
$

I want this shell script to terminate all its child processes when it exits regardless of how it's called. It'll eventually be started from a python and java application - and some form of cleanup is needed when the script exits - any options I should look into or any way to rewrite the script to clean itself up on exit?

like image 826
nos Avatar asked Oct 29 '09 16:10

nos


People also ask

How do I stop a shell script from running?

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.

How do you stop a bash script?

There are many methods to quit the bash script, i.e., quit while writing a bash script, while execution, or at run time. One of the many known methods to exit a bash script while writing is the simple shortcut key, i.e., “Ctrl+X”. While at run time, you can exit the code using “Ctrl+Z”.

How do you kill a command in bash?

To interrupt it, you can try pressing ctrl c to send a SIGINT. If it doesn't stop it, you may try to kill it using kill -9 <pid> , which sends a SIGKILL.


1 Answers

I would do something like this:

#!/bin/bash
trap : SIGTERM SIGINT

echo $$

find / >/dev/null 2>&1 &
FIND_PID=$!

wait $FIND_PID

if [[ $? -gt 128 ]]
then
    kill $FIND_PID
fi

Some explanation is in order, I guess. Out the gate, we need to change some of the default signal handling. : is a no-op command, since passing an empty string causes the shell to ignore the signal instead of doing something about it (the opposite of what we want to do).

Then, the find command is run in the background (from the script's perspective) and we call the wait builtin for it to finish. Since we gave a real command to trap above, when a signal is handled, wait will exit with a status greater than 128. If the process waited for completes, wait will return the exit status of that process.

Last, if the wait returns that error status, we want to kill the child process. Luckily we saved its PID. The advantage of this approach is that you can log some error message or otherwise identify that a signal caused the script to exit.

As others have mentioned, putting kill -- -$$ as your argument to trap is another option if you don't care about leaving any information around post-exit.

For trap to work the way you want, you do need to pair it up with wait - the bash man page says "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." wait is the way around this hiccup.

You can extend it to more child processes if you want, as well. I didn't really exhaustively test this one out, but it seems to work here.

$ ./test-k.sh &
[1] 12810
12810
$ kill 12810
$ ps -ef | grep find
$
like image 181
Carl Norum Avatar answered Sep 22 '22 15:09

Carl Norum