How to send a signal SIGINT from script to script?
Asked Answered
J

2

15

I want to trap a signal send from Script-A.sh to Script-B.sh so in Script-A.sh i use the command:

(Send SIGINT to Script-B.sh)
kill -2 $PID_Script-B.sh

And in Script-B.sh i catch the signal and call function Clean

trap 'Clean' 2

It does not work, instead the Script-B.sh is killed right away without performing the Clean !!

What i notice also is that if i want to send SIGINT from terminal to any script that traps it, a ctrl-c will be caught correctly, but not if i specify the signal via the command kill -2 $pid_of_script

Any idea about the difference between the two method to send the SIGINT (ctrl-c VS kill -2 $pid_of_script), and how i can send a SIGINT from a script to another?

Jolt answered 26/3, 2010 at 16:32 Comment(0)
A
15

I was able to reproduce the behavior you report. My hypothesis is that since the script is running from a non-interactive shell (as a child of a script) that SIGINT, which is a keyboard signal, is ignored.

From info bash:

Background processes are those whose process group ID differs from the terminal's; such processes are immune to keyboard-generated signals.

I have found that if you trap and kill using another signal such as SIGUSR1 it works.

Additional information from man bash:

Non-builtin commands run by bash have signal handlers set to the values inherited by the shell from its parent. When job control is not in effect, asynchronous commands ignore SIGINT and SIGQUIT in addition to these inherited handlers.

and

If bash is waiting for a command to complete and receives a signal for which a trap has been set, the trap will not be executed until the command completes.

and

Any trap on SIGCHLD is executed for each child that exits.

Affluent answered 26/3, 2010 at 22:47 Comment(7)
That first bit from bash(1) seems like a explanation. Also, zsh seems to work OK.Tumbling
Sorry for this late answer. You are right, not all signals are able to be catched for children but some. SIGUSR1 worked for me as well as SIGTERM, But not in all bash versions, cause i got a segmentation fault from a script in bash 3.00.16 when trying to send the signal from father to son !!! Other times using the same version it will just ignore the signal without catching it (in children level). But newer versions work well and propagate correctly all the signals. Thank you very much for your helpJolt
ok. run scriptA shell script and call scriptB (source it) like ". scriptB.sh param1 param2 .. paramN", that way, it'll catch clean for Sig 2/INTCreekmore
@ArunSangal: ...because scriptB is not a child then, it's treated as if it were part of scriptA.Affluent
SIGUSR1 doesn't work for me. What I do is start a scriptA in foreground and from another shell send the kill -SIGUSR1 pidof(scriptA). Nothing happens. What am I doing wrong ? function iAmDone { echo "Trapped Signal" exit 0 } trap iAmDone SIGUSR1 echo "Running... " tail -f /dev/null # Do nothing And from another shell I do kill -SIGUSR1 ps aux | grep [t]est_trap | awk '{print $2}'Osteophyte
@2.8a8a_G: You are grepping for "test_trap", but there's nothing that outputs that string as far as I can see. Try grepping for "tail". It's really hard to read code in comments. Perhaps you should ask a separate question.Affluent
#27435552Osteophyte
C
0

In script A: Trap function will look like following which will call trap_mesg() function in scriptA.sh. KILL Signal (2/INTerrupt, 5/TERMinate-default). All, you have to do is to get the PID of a runing scriptB.sh process/session once scriptB.sh is called from scriptA.sh (nohup ... & will give you or use ps command)

trap_mesg ()
{
 #...do something here for script B..
 # i.e. 
 kill -2 PID_of_ScriptB.sh_running_process_session
 sleep 10; #just in case, not reqd though.
 #show using ps -eAf|grep "scriptB" ... if null means, scriptB is gone. user is happy now.
 #...before actually exiting out...
 #show script A is exiting out as ScriptB is dead already, time for scriptA now.
 #...do something here..
}

#####################################
## Trap signals : INT, TERM. catch ##
#####################################
#Set NULL/Blank value to trap_call. This variable will help in running trap_mesg only once during the life of this script.
trap_call="";

trap 'if [ -z ${trap_call} ]; then trap_call="1"; trap_mesg ; fi' 2 15
##################################




Now, within scriptB.sh, do the same/similar but just for scriptB trap job (like calling clean).

clean ()
{
echo "karoge seva to milega meva"; 
rm -fr /some/folder_file
}

trap_mesg ()
{
 #...do something here JUST for script B trap message work..
 # i.e. 
 clean;
 #...do something here..
}

#####################################
## Trap signals : INT, TERM. catch ##
#####################################
#Set NULL/Blank value to trap_call. This variable will help in running trap_mesg only once during the life of this script.
trap_call="";

trap 'if [ -z ${trap_call} ]; then trap_call="1"; trap_mesg ; fi' 2 15
##################################

This way, you dont have to source/call scriptB.sh within scriptA.sh as ". scriptB.sh ...."

Creekmore answered 18/6, 2013 at 19:6 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.