从bash脚本运行时,Perl无法杀死自我pid

MrC*_*ket 4 terminal perl signals kill-process

以下代码在从终端运行时表现如预期:

perl -e 'kill -2, $$; warn HERE, $/'
Run Code Online (Sandbox Code Playgroud)

它在发送SIGINT到"HERE"之前发送并死亡:

~# perl -e 'kill -2, $$; warn HERE, $/'

~# echo $?
130
~#
Run Code Online (Sandbox Code Playgroud)

问题:从shell脚本运行时,相同的代码无法终止自身PID :

~# cat 1.sh
perl -e 'kill -2, $$; warn HERE, $/'
~#
~# sh 1.sh
HERE
~#
~# echo $?
0
~#
Run Code Online (Sandbox Code Playgroud)

另一方面,用killshell 替换perl的工作正常:

~# cat 2.sh
perl -e 'qx/kill -2 $$/; warn HERE, $/'
~#
~# sh 2.sh
~#
~# echo $?
130
~#
Run Code Online (Sandbox Code Playgroud)

不太明白这里发生了什么,请帮忙..

ike*_*ami 5

首先,

 kill -2, $$
Run Code Online (Sandbox Code Playgroud)

写得更好

 kill 2, -$$
Run Code Online (Sandbox Code Playgroud)

一个更好的选择是

 kill INT => -$$
Run Code Online (Sandbox Code Playgroud)

这些发送SIGINT到指定的进程组.


您的主要问题似乎是两个炮弹表现不同的原因.本节解释了这一点.

进程组代表一个应用程序.

当您从交互式shell启动程序时,它不是更大的应用程序的一部分,因此shell会为该程序创建一个新的进程组.

但是,脚本(即非交互式shell)创建的进程是脚本本身的同一应用程序的一部分,因此shell不会为它们创建新的进程组.

您可以使用以下方法将其可视化:

  • sh -i <<< 'perl -e '\''system ps => -o => "pid,ppid,pgrp,comm"'\''' 输出以下内容:

    $ 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
    
    Run Code Online (Sandbox Code Playgroud)

    在交互模式下,perlperlps节目组的负责人.

  • sh <<< 'perl -e '\''system ps => -o => "pid,ppid,pgrp,comm"'\''' 输出以下内容:

      PID  PPID  PGRP COMMAND
     8179  8171  8179 bash
    14584  8179 14584 sh
    14585 14584 14584 perl
    14586 14585 14584 ps
    
    Run Code Online (Sandbox Code Playgroud)

    在非交互模式下,shperlps程序组的负责人.


您的失败是由于未将信号发送到进程组的负责人(即应用程序)而导致的.如果你检查过,kill报告的错误是ESRCH("没有这样的过程").

ESRCHpid或进程组不存在.[...]

要终止当前进程的进程组,请替换不正确的进程

kill INT => -$$           # XXX
Run Code Online (Sandbox Code Playgroud)

kill INT => -getpgrp()    # Kill the application
Run Code Online (Sandbox Code Playgroud)

perl只需调用以下代码,您就可以成为自己的进程组的负责人:

setpgrp();
Run Code Online (Sandbox Code Playgroud)

测试:

$ 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
Run Code Online (Sandbox Code Playgroud)

这不是你通常想做的事情.


最后,Perl代码

kill INT => -$pgrp
Run Code Online (Sandbox Code Playgroud)

等效于kill命令行实用程序的以下调用:

kill -s INT -$pgrp
kill -INT -$pgrp
kill -2 -$pgrp
Run Code Online (Sandbox Code Playgroud)

-qx//程序中缺少,因此它将SIGINT发送到已识别的进程而不是已识别的程序组.