为什么我用 Perl 的 system() 启动的进程不是子进程?

发布于 2024-07-13 14:24:35 字数 722 浏览 8 评论 0原文

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

test.pl:test.sh

use POSIX;

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

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

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

waitpid($pid, 0);

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 并没有解决这个问题,尽管它澄清了这个问题。

Perl's system() starts a process, but breaks the parent/child relationship?

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

When I run test.pl, it finds and prints a correct pid of test.sh. But waitpid() returns -1 and test.pl exits. After test.pl exist, test.sh is still running.

It looks like test.sh is not a child of test.pl, which breaks waitpid(). Why does this happen and how to make system() behave? Is that because Perl clears children automatically? If yes, how can I solve a general task of waiting on a child explicitly?

Update:

answers below suggest using fork/exec. The initial problem is this:

  1. from a Perl script, run a command-line utility that starts a service. The utility exits but the service stays.

  2. after some time, find that service's pid and wait on it.

fork/exec doesn't solve this, although it clears up the question.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

卷耳 2024-07-20 14:24:36

一般来说,如果你不想 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

In general, you should manually fork and exec if you don't want Perl to help
you out. It's hard to determine exactly what you are doing, but I
think you want this:

my $pid = fork;
unless($pid){
    # child;
    exec(qw/sh test.sh/);
}

# parent
...
waitpid $pid, 0;

Personally, I prefer to let AnyEvent babysit:

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

Or, more generally: http://github.com/jrockway/anyevent-subprocess/tree/master

活雷疯 2024-07-20 14:24:36

为了进一步解释 Liudvikas 的答案 -

system("./test.sh &")
 |
 |--> (P) /bin/sh (to run test.sh)
       |
       |--> (P) test.sh & (still running)

(P) - process

在分叉并运行 test.sh 脚本后,/bin/sh shell(Perl 系统调用的子级)退出,因此您从 waitpid() 获得 -1 返回值。

To further explain Liudvikas' answer -

system("./test.sh &")
 |
 |--> (P) /bin/sh (to run test.sh)
       |
       |--> (P) test.sh & (still running)

(P) - process

After fork'ing and running the test.sh script the /bin/sh shell, which was the child of the Perl system call, exits and so you get a -1 return value from waitpid().

一个人的旅程 2024-07-20 14:24:35

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

The test.sh process is not your child process. The system() forked a shell (which is your child), that shell forked a child that ran the test.sh program. The shell that was your child exited.

九命猫 2024-07-20 14:24:35

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

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

尽管由于 shell 脚本处于无限循环中,所以它将永远等待。

What you probably want to do is something like this:

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

Though since the shell script is in an infinite loop, it will wait forever.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文