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

标签 perl terminal signals kill-process

从终端运行时,以下代码的行为符合预期:

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

它向自己发送SIGINT并在到达“HERE”之前死亡:

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

~# echo $?
130
~#

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

~# cat 1.sh
perl -e 'kill -2, $$; warn HERE, $/'
~#
~# sh 1.sh
HERE
~#
~# echo $?
0
~#

另一方面,用 shell 的 kill 替换 perl 的 kill 就可以了:

~# cat 2.sh
perl -e 'qx/kill -2 $$/; warn HERE, $/'
~#
~# sh 2.sh
~#
~# echo $?
130
~#

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

最佳答案

首先,

 kill -2, $$

最好写成

 kill 2, -$$

更好的选择是

 kill INT => -$$

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

<小时/>

您的主要问题似乎是为什么两个 shell 的行为不同。本节对此进行了解释。

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

当您从交互式 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
    

    在交互模式下,perl位于 perl 的头部和ps的节目组。

  • 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
    

    在非交互模式下,sh位于 perl 的头部和ps的节目组。

<小时/>

您的失败是由于未将信号发送到进程组的头部(即应用程序)而导致的。如果您检查过,错误 kill报告为ESRCH (“没有这样的过程”)。

ESRCH The pid or process group does not exist. [...]

杀死当前进程的进程组,替换不合适的

kill INT => -$$           # XXX

kill INT => -getpgrp()    # Kill the application
<小时/>

您可以将您的perl通过简单地调用以下命令来获取其自己的进程组的头:

setpgrp();

测试:

$ 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

这不是您通常想做的事情。

<小时/>

最后是Perl代码

kill INT => -$pgrp

相当于以下调用kill命令行实用程序:

kill -s INT -$pgrp
kill -INT -$pgrp
kill -2 -$pgrp

您失踪了-在你的qx//程序,因此它向已识别的进程而不是已识别的程序组发送 SIGINT。

关于从 bash 脚本运行时,Perl 无法杀死 self pid,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/43845000/

相关文章:

perl - 如何弃用基于 Moose 的类中的属性

angular - 如何在本地将 JSON 数据从 perl 脚本传递到 Angular Controller

perl - 如何将 Perl 对象转换为 JSON,反之亦然

linux - 拆分以分号分隔的单词

bash - 使用 GNU screen 时如何避免 emacs(或 vi)在关闭后留在 screen 上?

c - 超过超时限制后未从 alarm() 触发信号处理程序

c++ - Qt C++信号转Qml

perl - 如何在 OSX 上覆盖 httpd.conf 中的 @INC 设置

ruby-on-rails - Rails - 服务器已经在运行

matlab - 从噪声信号/电压测量中提取神经元尖峰时间的最佳方法