4

Perl 的 system() 启动一个进程,但打破了父/子关系?

测试.pl:

use POSIX;

system("./test.sh &");

my $pid = `ps -C test.sh -o pid=`;

print "pid: -$pid-\n";

waitpid($pid, 0);

测试.sh:

while true
do
    sleep 1
done

当我运行 test.pl 时,它会找到并打印出 test.sh 的正确 pid。但是 waitpid() 返回 -1 并且 test.pl 退出。test.pl 存在后,test.sh 仍在运行。

看起来 test.sh 不是 test.pl 的子级,它会破坏 waitpid()。为什么会发生这种情况以及如何使 system() 行为?那是因为 Perl 会自动清除孩子吗?如果是,我该如何解决明确等待孩子的一般任务?

更新:

下面的答案建议使用 fork/exec。最初的问题是这样的:

  1. 从 Perl 脚本,运行启动服务的命令行实用程序。实用程序退出,但服务保留。

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

fork/exec 没有解决这个问题,尽管它解决了这个问题。

4

4 回答 4

16

test.sh 进程不是您的子进程。分叉了一个外壳(这system()是你的孩子),那个外壳分叉了一个运行 test.sh 程序的孩子。作为您孩子的 shell 退出了。

于 2009-02-17T15:17:35.583 回答
6

您可能想要做的是这样的事情:

my $pid = fork || exec './test.sh';
print "pid: -$pid-\n";
waitpid($pid, 0);

虽然由于 shell 脚本处于无限循环中,但它会永远等待。

于 2009-02-17T15:23:26.117 回答
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

于 2009-02-17T15:23:55.960 回答
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 返回值。

于 2009-02-17T15:23:17.957 回答