为什么我从Perl的system()开始是一个子进程?

时间:2009-02-17 15:11:43

标签: perl unix process system waitpid

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。最初的问题是:

  1. 从Perl脚本运行一个启动服务的命令行实用程序。该实用程序退出但服务仍然存在。

  2. 一段时间后,找到该服务的pid并等待它。

  3. fork / exec没有解决这个问题,虽然它解决了这个问题。

4 个答案:

答案 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返回值。