从另一个环境调用 Perl 在后台

Posted

技术标签:

【中文标题】从另一个环境调用 Perl 在后台【英文标题】:Perl on background when invoked from another env 【发布时间】:2015-05-30 00:41:02 【问题描述】:

我有一个应该在后台做一些工作的 Perl 脚本。这很好地描述了 - 我分叉,杀死(返回0)父母并在孩子身上完成工作。当我直接从 shell 运行它时,它按预期工作(即在杀死父级后立即返回到 shell 并继续在后台运行)。但是如果我从另一个环境运行它,例如从 php 通过执行

    php -r "passthru('my-perl-script.pl')"

它在孩子完成后返回到 shell。任何想法为什么会发生这种情况?

谢谢!

编辑: 这是我使用的 Perl 代码:

#!/usr/bin/env perl
use strict;
use warnings;

local $| = 1;

# fork the process - returns child pid to the parent process and 0
# to the child process
print ' [FORKING] ';
my $pid = fork();
error('Failed to fork: $@') and exit 1 if $@;

# exit parent
print ' [KILLING PARENT] ';
exit 0 if $pid;

# continue as child process
print " [CONTINUING AS CHILD] \n";

# wait 3 secs (for testing) and exit
sleep 3;
print " [DONE]\n";
exit 1;

直接执行时的输出:

$ ./background-test.pl
 [FORKING]  [KILLING PARENT]  [KILLING PARENT]  [CONTINUING AS CHILD]
$  [DONE] 

通过 PHP 执行时的输出:

$ php -r "system('./background-test.pl');"
$ [FORKING]  [KILLING PARENT]  [KILLING PARENT]  [CONTINUING AS CHILD]
  # ... 3 seconds wait ... 
  [DONE]
$

我的问题是为什么 Perl 脚本在从其他环境调用时不会断开连接(这里 PHP 只是一个示例)。

谢谢!

【问题讨论】:

请提供该问题的最小可运行演示。 我添加了我用来演示问题的示例 Perl 代码。谢谢 【参考方案1】:

如果我理解正确,你是说 PHP 正在等待孙子结束,即使孩子退出了。

system 不会返回,因为php 收集孩子的 STDOUT,即孙子继承的相同 STDOUT。在 Linux 系统上,这可以通过在 Perl 脚本中添加以下内容来查看:

system("ls -l /proc/$$/fd");

从外壳:

lrwx------ 1 ikegami ikegami 64 Jun  1 14:07 1 -> /dev/pts/0

来自 PHP:

l-wx------ 1 ikegami ikegami 64 Jun  1 14:08 1 -> pipe:[10052926]

通常,当您解除进程时,您会重新打开其 STDIN、STDOUT 和 STDERR,将它们重定向到 /dev/null 或日志文件。

open(STDIN,  '<',  '/dev/null') or die $!;
open(STDOUT, '>',  '/dev/null') or die $!;
open(STDERR, '>>', '/var/log/application.log') or die $!;

通常,当您解除进程时,您也会调用POSIX::setsid()

【讨论】:

感谢您的回复。系统工作原理相同,子进程终止后返回shell。 嗯似乎将 STDOUT 重定向到 /dev/null 可以解决问题。谢谢!

以上是关于从另一个环境调用 Perl 在后台的主要内容,如果未能解决你的问题,请参考以下文章

从另一个 Perl 脚本内部调用 Perl 搜索和替换命令时不起作用

可以将 perl 脚本的执行权限限制为从另一个 perl 脚本调用吗?

Python - 调用 perl 作为子进程 - 等待完成其后台进程并打印到 shell

从另一个选项卡调用 popToRootViewController

在 /etc/init.d 脚本中调用守护进程被阻塞,不在后台运行

通过从perl脚本调用的批处理文件设置环境变量