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并没有解决这个问题.
test.sh进程不是您的子进程.该system()
分叉外壳(这是你的孩子),壳牌分叉运行该程序test.sh一个孩子.你孩子的外壳退出了.
你可能想做的是这样的:
my $pid = fork || exec './test.sh'; print "pid: -$pid-\n"; waitpid($pid, 0);
虽然由于shell脚本处于无限循环中,但它将永远等待.
通常,如果您不希望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
为了进一步解释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返回值.