|

Bash – Handeling children and termination signals

First and unrelated – this is my birthday. It reminds me that another year passed, and generally speaking, I do not take this too well…

Due to massive SPAM attacks, my commenting system is turned off for a while now, and I need to see how I can re-enable it safely.

Bash – here we go.

When you want a single script to spawn several commands in parallel, the best way is to use the ampersand at the end of each command, example:

/usr/bin/find / -name 123 &

/bin/grep -r abc / &

etc.

If you do not want the output from these commands to mix together, you would probably wish to redirect it to a file, for example (redirecting all outputs):

/usr/bin/find / -name 123 &>/tmp/find.out &

/bin/grep -r abc / &>/tmp/grep.out &

You can later “cat” the two files in your own desired order.

This adds two interesting issues – the first is about how you can tell that both commands finished. There are several methods, such as collecting their PIDs, and looping with “sleep” until they are no longer there. Alternate, and more elegant method is by using “wait“. This command will wait for both commands (in our example. As many commands as you have forked to the background) to finish, and only then continue. So we can add, in our example, the following lines:

wait

cat /tmp/find.out

cat /tmp/grep.out

This will insure that both outputs are not mixed together, and are readable.

The second issue caused by the output redirection we’ve added earlier is the handling of killing these commands. Let’s assume that our script is time-limited, and if it exceeds its given time limits, it gets killed. In this case, this script will be killed, however, its children will not die, and will become owned by init, PID 1. This will keep these commands running. Try to assume, for that matter, that every 10 minutes we run the main script, and that it is limited to these ten minutes. We might kill the system’s I/O performance since we might reach a case where several “find” commands are running in parallel – each invoked by our main script at a different time.

To handle such case, we can use the command “trap“. It allows us to handle signals in a method we desire. notice that if you capture SIGTERM (kill -15 – the default kill) and misuse it, the only method of stopping the main script will be by invoking SIGKILL (kill -9) on it, which bypasses all trap directives.

In our example, let’s add this (assume we are aware of each PID)

trap “kill $PID1 $PID2 ; exit 0” SIGTERM

So we can sum up our example script to be like this:

/usr/bin/find / -name 123 &>/tmp/find.out &

PID1=$!

/bin/grep -r abc / &>/tmp/grep.out &

PID2=$!

trap “kill $PID1 $PID2 ; exit 0” SIGTERM

wait

cat /tmp/find.out

cat /tmp/grep.out

This wraps it up. Hope it helps.

Similar Posts

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.