How to propagate a signal through a collection of scripts?
Asked Answered
G

4

22

I have an collection of scripts which are controlled by a main one. I want to trap the signal ctrl+c in the main script and propagate it to the others. The other scripts should trap this signal as well ( from the main script ) and do some clean-up ...

I have tried to send kill -s SIGINT to the children, but they seem they are unable to catch the signal( even if trap 'Cleanup' SIGINT being defined on the children scripts )

Any clues how to realize this?

Grin answered 26/3, 2010 at 18:46 Comment(2)
It would be helpful if you show specific examples of an abbreviated parent and child.Indefatigable
See my answer at your other question for a possible solution. #2525437Indefatigable
B
20

The following example demonstrates a parent script that does something (sleep 5) after it starts two children that do their own thing (also sleep 5). When the parent exits (for whatever reason) it signals the children to terminate (don't SIGINT, termination is signaled by SIGTERM, also the default kill signal). The children then do their thing on reception of SIGTERM. If the children are scripts of their own, I recommend you change the trap on TERM into a trap on EXIT so that the children clean up no matter what the cause of their termination be (so long as it's trappable).

Notice my use of wait. Bash does not interrupt running non-builtin commands when it receives a signal. Instead, it waits for them to complete and handles the signal after the command is done. If you use wait, bash stops waiting immediately and handles the signal right away.

#!/usr/bin/env bash

trap 'echo parent shutting down; kill $(jobs -p)' EXIT

{ trap 'echo child 1 signaled' TERM; sleep 5 & wait; } &
{ trap 'echo child 2 signaled' TERM; sleep 5 & wait; } &

sleep 5
Bactria answered 5/8, 2010 at 11:53 Comment(2)
how does the sleep 5 get killed in the childs when a TERM signal is sent to this script ?Sidonia
Shouldn't the sleep in the children be longer than 5 for the example? Like this, they finish before the sleep in the parent is done and kill can't find the jobs any longer.Ai
K
4

Have you tried to : 1) Setup your traps in every script (master / childs) where you need them 2) Send to the master a kill with it's PID negated, to kill the whole process group, I mean :

kill -15 -$PID

man kill | grep -C1 Negative

Kaliningrad answered 20/3, 2011 at 14:20 Comment(0)
C
0

MAIN PARENT SCRIPT HEADER BEFORE THE MAIN LOOP:::

#Catch control-c and clean up testd instances if necessary
cleanup () {
    clear
    echo "Caught Signal.  Shutting Down MAIN."
    if [ "$MAIN_on" -eq 1 ]
    then
    M_shutdown
    fi
    exit 1
  }

In the main body of the script, as you spawn subprocesses you maintain an array with the proc ids of each. To load the PID into the array set the value to last spawned process e.g. put the following after each sub-shell spawn.

proc_id_array[1]=$!

Contents of the M_shutdow would be something like...

M_shutdown () {

    if [ "$MAIN_on" -eq 1 ]
    then
    echo "Stopping Main"
    echo "shutting down active subscripts"
    count_proc_id=1


while [ "$count_proc_id" -lt "$max_proc_id" ]
        do

            kill ${proc_id_array[$count_proc_id]} > /dev/null 2>&1
            DATE=$(date +%m%d%y-%k:%M)
            echo "$DATE: ${proc_name_array[$count_proc_id]} \(PID: ${proc_id_array[$count_proc_id]}\) stopped." >> $logfile             
            proc_id_array[$count_proc_id]="A"
            count_proc_id=`expr $count_proc_id + 1`
        done


        echo "MAIN stopped"
        MAIN_on=0

        sleep 5
        else
        echo "MAIN already stopped."
        sleep 1
        fi
    }
Courante answered 9/8, 2010 at 14:41 Comment(0)
S
-2

I'm not sure what do you mean by "other scripts should trap this signal from the main script"? How can a subprocess script use code in the main script to trap a signal?

I don't want to try and write much code for you because I don't know exactly what you mean by "scripts controlled by a main one" either, but presumably you launch some subprocesses then have a control loop which checks if the other scripts have exited, and can grab their exit status? If that's the case, the thing that makes the most sense to me is for each script to do its own trapping and cleanup. When the main script traps a signal, it can if desired pass the signal along to all the children (via kill -s <signal> pid). When a child process traps a signal, it can return an exit status indicating that it was terminated by that signal. The main can then handle that exit status appropriately - perhaps in the same way as if it'd received that particular signal itself. (Shell functions are your friend.)

Shawndashawnee answered 26/3, 2010 at 19:2 Comment(3)
Actually i send kill -s <signal> pid to the children but they can not catch it (even with trap 'Cleanup' 2 being defined). so the children are killed without clean-up. The main script does not know much about what the children are doing, so he can not handle the clean-up by itselfGrin
@debugger: What do you mean the children can't catch the signal? Is that trap in the main script? It needs to be in the children.Shawndashawnee
Jefromi: traps are specified on both main and children scripts, although they call different functions. So the main script catch the ctrl-csignal and send signals to the different children. Then there are traps defined on children that "should" catch the signal from the main script and call a specific functionGrin

© 2022 - 2024 — McMap. All rights reserved.