How can bash script do the equivalent of Ctrl-C to a background task?

Solution 1:

For anyone wondering, this is how you launch childs in the background and kill them on ctrl+c:

#!/usr/bin/env bash
command1 &
pid[0]=$!
command2 &
pid[1]=$!
trap "kill ${pid[0]} ${pid[1]}; exit 1" INT
wait

Solution 2:

Read this : How to send a signal SIGINT from script to script ? BASH

Also from info bash

   To facilitate the implementation of the user interface to job  control,
   the operating system maintains the notion of a current terminal process
   group ID.  Members of this process group (processes whose process group
   ID is equal to the current terminal process group ID) receive keyboard-
   generated signals such as SIGINT.  These processes are said  to  be  in
   the  foreground.  Background processes are those whose process group ID
   differs from the terminal's; such processes are immune to keyboard-gen‐
   erated signals. 

So bash differentiates background processes from foreground processes by the process group ID. If the process group id is equal to process id, then the process is a foreground process, and will terminate when it receives a SIGINT signal. Otherwise it will not terminate (unless it is trapped).

You can see the process group Id with

ps x -o  "%p %r %y %x %c "

Thus, when you run a background process (with &) from within a script, it will ignore the SIGINT signal, unless it is trapped.

However, you can still kill the child process with other signals, such as SIGKILL, SIGTERM, etc.

For example, if you change your script to the following it will successfully kill the child process:

#!/bin/bash

if [ "$1" = "--child" ]; then
  sleep 1000
elif [ "$1" = "--parent" ]; then
  "$0" --child &
  for child in $(jobs -p); do
    echo kill "$child" && kill "$child"
  done
  wait $(jobs -p)

  else
  echo "Must be invoked with --child or --parent."
fi

Output:

$ ./test.sh --parent
kill 2187
./test.sh: line 10:  2187 Terminated              "$0" --child

Solution 3:

somecommand &

returns a pid of the child in $!

somecommand &
pid[0]=$!
anothercommand &
pid[1]=$!
trap "kill ${pid[0]} ${pid[1]}; exit 1" INT
wait

I would start with this model rather than with bash job control (bg, fg, jobs). Normally init inherits and reaps orphan processes. What problem are you trying to solve?