Perl fails to kill self pid when running from bash script

kill-process, perl, signals, terminal

Solution

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.

Problem

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..

Original source