Following code behaves as expected when running from terminal:
perl -e 'kill -2, $$; warn HERE, $/'
It sends itself SIGINT
and dies before reaching "HERE":
~# perl -e 'kill -2, $$; warn HERE, $/'
~# echo $?
130
~#
The problem: same code fails to kill self PID when running from shell script:
~# cat 1.sh
perl -e 'kill -2, $$; warn HERE, $/'
~#
~# sh 1.sh
HERE
~#
~# echo $?
0
~#
On the other hand, replacing perl's kill
by a shell's one works OK:
~# cat 2.sh
perl -e 'qx/kill -2 $$/; warn HERE, $/'
~#
~# sh 2.sh
~#
~# echo $?
130
~#
Not really understand what is happening here, please help..
First of all,
kill -2, $$
is better written as
kill 2, -$$
An even better alternative is
kill INT => -$$
These send SIGINT
to the specified process group.
Your main question appears to be why the two shells behave differently. This section explains that.
The process group represents an application.
When you launch a program from an interactive shell, it's not part of a larger application, so the shell creates a new process group for the program.
However, processes created by a script (i.e. a non-interactive shell) are part of the same application as the script itself, so the shell doesn't create a new process group for them.
You can visualize this using the following:
sh -i <<< 'perl -e '\''system ps => -o => "pid,ppid,pgrp,comm"'\'''
outputs the following:
$ perl -e 'system ps => -o => "pid,ppid,pgrp,comm"'
PID PPID PGRP COMMAND
8179 8171 8179 bash
14654 8179 14654 sh
14655 14654 14655 perl
14656 14655 14655 ps
$ exit
In interactive mode, perl
is at the head of perl
and ps
's program group.
sh <<< 'perl -e '\''system ps => -o => "pid,ppid,pgrp,comm"'\'''
outputs the following:
PID PPID PGRP COMMAND
8179 8171 8179 bash
14584 8179 14584 sh
14585 14584 14584 perl
14586 14585 14584 ps
In non-interactive mode, sh
is at the head of perl
and ps
's program group.
Your failures are the result of not sending the signal to the head of the process group (i.e. the application). Had you checked, the error kill
reported was ESRCH
("No such process").
ESRCH
The pid or process group does not exist. [...]
To kill the current process's process group, replace the improper
kill INT => -$$ # XXX
with
kill INT => -getpgrp() # Kill the application
You can make your perl
the head of its own process group by simply calling the following:
setpgrp();
Test:
$ sh <<< 'perl -e '\''system ps => ( -o => "pid,ppid,pgrp,comm" )'\'''
PID PPID PGRP COMMAND
8179 8171 8179 bash
16325 8179 16325 sh
16326 16325 16325 perl
16327 16326 16325 ps
$ sh <<< 'perl -e '\''setpgrp(); system ps => ( -o => "pid,ppid,pgrp,comm" )'\'''
PID PPID PGRP COMMAND
8179 8171 8179 bash
16349 8179 16349 sh
16350 16349 16350 perl
16351 16350 16350 ps
That's not something you normally want to do.
Finally, the Perl code
kill INT => -$pgrp
is equivalent to the following call of the kill
command-line utility:
kill -s INT -$pgrp
kill -INT -$pgrp
kill -2 -$pgrp
You were missing -
in your qx//
program, so it was sending SIGINT to the identified process rather than the identified program group.