Simple job control in bash

23 Aug 2017 09:03 bash

What?

As part of our system test suite, I need to run a bunch of programs at the same time, and have them restart if they crash.

I also want them all to die at the same time if I stop the foreground process.

I can’t use monit or upstart or systemd, because these aren’t system processes; I’m running them locally (probably from a Makefile). I also spent some time messing around with forever, but I couldn’t persuade it to run non-node processes.

Let’s use bash instead…

The plan

The plan here is to run a couple of netcat instances, listening on different ports. These will stand in for our real processes.

I’m going to run them without the -k (keep listening) switch, because that gives me an easy way to make them exit (by sending them data).

We can send them data with echo "Hello World!" > /dev/tcp/localhost/9220.

The script

#!/bin/bash

# When the script exits, kill the current process group.
trap "kill -- -$BASHPID" EXIT

# Run the command in the background.
# If it stops, restart it.
(while true; do
    nc -l 9220
done) &

(while true; do
    nc -l 9221
done) &

# Wait indefinitely (for Ctrl+C).
cat

If you want a short delay before restarting the process…

(while true; do
    nc -l 9220
    sleep 1
done) &

If you want the process to restart only if it exits with a non-zero status:

(unless nc -l 9220; do
    sleep 1
done) &