的Perl未能杀死自己的pid从bash脚本运行时
下面的代码的行为,从终端运行当预期:的Perl未能杀死自己的pid从bash脚本运行时
perl -e 'kill -2, $$; warn HERE, $/'
它自己发送SIGINT
并达到“HERE”前去世:
~# perl -e 'kill -2, $$; warn HERE, $/'
~# echo $?
130
~#
问题:运行时,同一代码无法自行清除自动PID:
~# cat 1.sh
perl -e 'kill -2, $$; warn HERE, $/'
~#
~# sh 1.sh
HERE
~#
~# echo $?
0
~#
在另一方面,取代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
pid或进程组不存在。 [...]
杀死当前进程的进程组,与
kill INT => -getpgrp() # Kill the application
更换不当
kill INT => -$$ # XXX
你可以让你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发送给已识别的进程而不是已识别的程序组。
我很失望,你选择了“答案”,甚至没有回答你的问题(为什么两个shell的行为不同)。 – ikegami
对不起,听到你很失望,不是故意的。对我来说,两个解释看起来都非常平等。我错了吗?你为什么认为挑选的人不回答我的问题? – MrCricket
两种解释?我只看到一个。我们的两个答案都解释了为什么过程组工作的原因,但这不是你问为什么这两个shell的行为不同,而他们的其他答案根本就没有解释。只有我的答案(应用程序的概念)。我错过了什么? ///事实上,另一个答案声称这两个shell可以表现完全相同(通过说非流行的shell创建的流程组只有*很可能*),但这是错误的! – ikegami
它正常工作,以这种方式:
perl -E 'say "kill "INT", $$; warn HERE, $/'
perl -E 'say "kill 2, $$; warn HERE, $/'
kill手册页说:
负信号名称是相同的负信号数, 杀死进程组,而不是过程。例如,kill '-KILL',$ pgrp和kill -9,$ pgrp将向指定的整个 进程组发送SIGKILL。这意味着你通常想要使用正数 而不是负数信号。
从您的交互式终端中,perl进程杀死它所属的进程组。 (shell在自己的进程组中运行perl。)外壳报告这个不寻常的终止在$?
:
t0 interactive shell (pid=123, pgrp=123) | t1 +------> perl -e (pid=456, pgrp=456, parent=123) | | t2 (wait) kill(-2, 456) (in perl, same as kill pgrp 456 w/ SIGINT) | | t3 (wait) *SIGINT* | t4 report $?
从你shell脚本,perl的进程杀死(可能)不存在程序组,然后成功退出。您的交互式shell创建一个新的进程组来运行您的shell脚本,然后该脚本在同一个进程组中作为子进程运行perl。
t0 shell (pid=123, pgrp=123) | t1 +-------> shell:1.sh (pid=456, pgrp=456, parent=123) | | t2 (wait) +-------------> perl -e (pid=789, pgrp=456, parent=456) | | | t3 (wait) (wait) kill pgrp 789 with SIGINT (error: no such pgrp) | | | t4 (wait) (wait) exit success | | t5 (wait) exit success | t6 report $?
在你backticked(qx//
)例如,你的交互shell启动一个新的进程组一个shell进程。 (这里并不重要,但该进程在同一个进程组中运行perl。)然后,Perl以自己的孩子身份运行系统kill
命令,,其语义不同于perl kill
的语义。这个grandchild命令直接发送一个SIGINT给perl PID,而不是一个SIGINT给一个进程组。 Perl终止,并且退出代码作为脚本的退出代码传递,因为它是脚本中的最后一个命令。
该图是比以前的忙一点:
t0 shell (pid=123, pgrp=123) | t1 +-------> shell:2.sh (pid=456, pgrp=456, parent=123) | | t2 (wait) +----------> perl -e (pid=789, pgrp=456, parent=456) | | | t3 (wait) (wait) +---------> /bin/kill SIGINT 789 | | | | t4 (wait) (wait) *SIGINT* exit success | | t5 (wait) return $? | t6 report $?
顺便说,'杀INT => - $$'是一个更好的写入'杀-2,$$'的方式。 – ikegami