Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Perl fails to kill self pid when running from bash script

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

like image 778
MrCricket Avatar asked Jan 04 '23 01:01

MrCricket


1 Answers

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.

like image 169
ikegami Avatar answered Jan 13 '23 23:01

ikegami