Roy Prins
Roy Prins

Reputation: 3080

Parallel processes in bash, kill with Ctrl C

Just made my first bash script. It spawns a http-server process in parallel for each folder in a certain directory.

Here is what I have:

PORT=8001
cd websitesfolder
for d in */ ; do
  http-server $d -p $PORT &
  let "PORT++" 
done

This does spawn the http-servers, but when I exit with Ctrl C, the processes are not killed.

I implemented this without a loop first, and adding && fg I was able to kill the processes using Ctrl+C

http-server dir1 -p 8001 & http-server dir2 -p 8002 && fg

Is something similar possible with my looped solution?

edit: system is macOS

Upvotes: 1

Views: 1436

Answers (1)

Charles Duffy
Charles Duffy

Reputation: 295443

A simple approach -- albeit not completely reliable, should a process die and have something else be assigned its PID number -- is simply to maintain an array of PIDs:

#!/usr/bin/env bash

pids=( )    
port=8001

graceful_shutdown() {
  (( ${#pids[@]} )) && kill "${pids[@]}"
}

cd websitesfolder || exit
for d in */ ; do
  http-server "$d" -p "$port" & pids+=( "$!" )
  (( ++port ))
done

trap graceful_shutdown EXIT
for pid in "${pids[@]}"; do
  wait "$pid" || (( retval |= $? ))
done
exit "$retval"

A better approach is to have a lockfile per port, or to use fuser -k to kill the processes that actually hold the ports open directly, rather than assuming that you know the PIDs:

#!/usr/bin/env bash

graceful_shutdown() {
  fuser -k "$lockdir"/*
}

lockdir=/var/run/mydir # this needs to exist
port=8001
pids=( )

cd websitesfolder || exit

for d in */; do
  (exec 3>"$lockdir/$port" &&
   flock -x 3 &&
   exec http-server "$d" -p "$port") & pids+=( "$!" )
done

trap graceful_shutdown EXIT
for pid in "${pids[@]}"; do
  wait "$pid" || (( retval |= $? ))
done
exit "$retval"

Upvotes: 4

Related Questions