n-a*_*der 4 unix perl system process 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);
Run Code Online (Sandbox Code Playgroud)
test.sh:
while true
do
sleep 1
done
Run Code Online (Sandbox Code Playgroud)
当我运行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并没有解决这个问题.
你可能想做的是这样的:
my $pid = fork || exec './test.sh';
print "pid: -$pid-\n";
waitpid($pid, 0);
Run Code Online (Sandbox Code Playgroud)
虽然由于shell脚本处于无限循环中,但它将永远等待.
通常,如果您不希望Perl帮助您,您应该手动fork和exec.很难确切地确定你在做什么,但我认为你想要这个:
my $pid = fork;
unless($pid){
# child;
exec(qw/sh test.sh/);
}
# parent
...
waitpid $pid, 0;
Run Code Online (Sandbox Code Playgroud)
就个人而言,我更愿意让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
Run Code Online (Sandbox Code Playgroud)
或者,更一般地说: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
Run Code Online (Sandbox Code Playgroud)
在fork'ing并运行test.sh脚本后,/ bin/sh shell(它是Perl系统调用的子代)退出,因此从waitpid()获得-1返回值.