Perl的system()启动一个进程,但会破坏父/子关系吗?
test.pl:
use POSIX;
system("./test.sh &");
my $pid = `ps -C test.sh -o pid=`;
print "pid: -$pid-\n";
waitpid($pid, 0);
test.sh:
while true
do
sleep 1
done
当我运行test.pl时,它会找到并打印一个正确的test.sh.但是waitpid()返回-1并且test.pl退出。在test.pl存在之后,test.sh仍在运行。
看起来test.sh不是test.pl的子代,它会破坏waitpid()。为什么会发生这种情况以及如何使system()表现出来?这是因为Perl会自动清除孩子吗?如果是,我该如何解决明确等待儿童的一般性任务?
更新
下面的答案建议使用fork / exec。最初的问题是:
从Perl脚本运行一个启动服务的命令行实用程序。该实用程序退出但服务仍然存在。
一段时间后,找到该服务的pid并等待它。
fork / exec没有解决这个问题,虽然它解决了这个问题。
答案 0 :(得分:16)
test.sh进程不是您的子进程。 system()
分叉了一个shell(这是你的孩子),该shell分叉了一个运行test.sh程序的子代。你孩子的外壳退出了。
答案 1 :(得分:6)
你可能想要做的是这样的事情:
my $pid = fork || exec './test.sh';
print "pid: -$pid-\n";
waitpid($pid, 0);
虽然shell脚本处于无限循环中,但它会永远等待。
答案 2 :(得分:6)
通常,如果您不希望Perl提供帮助,您应该手动fork和exec 你出去。很难确切地确定你在做什么,但我 认为你想要这个:
my $pid = fork;
unless($pid){
# child;
exec(qw/sh test.sh/);
}
# parent
...
waitpid $pid, 0;
就个人而言,我更愿意让AnyEvent照看孩子:
my $done = AnyEvent->condvar;
my $pid = fork;
unless( $pid ) { ... }
my $w = AnyEvent->child (
pid => $pid,
cb => sub {
my ($pid, $status) = @_;
warn "pid $pid exited with status $status";
$done->send;
},
);
$done->recv; # control resumes here when child exits
或者,更一般地说:http://github.com/jrockway/anyevent-subprocess/tree/master
答案 3 :(得分:5)
进一步解释Liudvikas的回答 -
system("./test.sh &")
|
|--> (P) /bin/sh (to run test.sh)
|
|--> (P) test.sh & (still running)
(P) - process
在fork'ing并运行test.sh脚本后,/ bin / sh shell(它是Perl系统调用的子代)退出,因此从waitpid()获得-1返回值。