【问题标题】:How can I run Perl system commands in the background?如何在后台运行 Perl 系统命令?
【发布时间】:2011-02-12 06:46:00
【问题描述】:
#!/usr/bin/env perl
use warnings; use strict;
use 5.012;
use IPC::System::Simple qw(system);

system( 'xterm', '-geometry', '80x25-5-5', '-bg', 'green', '&' );

say "Hello";
say "World";

我试过这个在后台运行 xterm-command,但它不起作用:

找不到shell的绝对路径:&

什么是让它发挥作用的正确方法?

【问题讨论】:

  • 在这里测试似乎对我有用。你想完成什么?
  • 是不是应该打开终端,然后在终端打印hello world?
  • 或者您只是尝试进行异步调用以打开终端?
  • “说”只是为了检查 xterm 是否在后台运行。
  • 前段时间我想通了(仅使用一个参数),但与此同时我忘记了它(同时形成“平均”时间?)。我希望我不会忘记第二次。

标签: perl background system


【解决方案1】:

这不仅仅是对 Perl 的解释。同样的问题在 C 和其他语言下也是如此。

首先了解system命令的作用:

  1. 分叉
  2. 子进程下调用exec
  3. 父进程正在等待分叉的子进程完成

传递多个参数或一个参数都没有关系。不同之处在于,如果有多个参数,则直接执行命令。有一个参数,命令被shell包裹,最后执行为:

/bin/sh -c your_command_with_redirections_and_ambersand

当您将命令作为 some_command par1 par2 & 传递时,则在 Perl 解释器和命令之间使用 shbash 进程作为包装器,它正在等待 some_command 完成。您的脚本正在等待 shell 解释器,不需要额外的 waitpid,因为 Perl 的函数 system 会为您完成。

当您想直接在脚本中实现此机制时,您应该:

  1. 使用 fork 功能。参见示例:http://users.telenet.be/bartl/classicperl/fork/all.html
  2. 在子条件(if)下,使用exec函数。您的用户类似于 system,请参阅手册。注意,exec 导致子进程程序/内容/数据被执行的命令覆盖。
  3. 在父条件下(如果,fork 以非零值退出),您使用 waitpid,使用 fork 函数返回的 pid。

这就是您可以在后台运行该进程的原因。我希望这很简单。

最简单的例子:

if (my $pid = fork) { #exits 0 = false for child process, at this point is brain split
  # parent ($pid is process id of child)
  # Do something what you want, asynchronously with executed command
  waitpid($pid);  # Wait until child ends
  # If you don't want to, don't wait. Your process ends, and then the child process will be relinked
  # from your script to INIT process, and finally INIT will assume the child finishing.
  # Alternatively, you can handle the SIGCHLD signal in your script
}
else {
  # Child
  exec('some_command arg1 arg2'); #or exec('some_command','arg1','arg2');
  #exit is not needed, because exec completely overwrites the process content
}

【讨论】:

    【解决方案2】:

    注意system 的列表形式专门& 等字符视为shell 元字符。

    来自perlfaq8How do I start a process in the background?的回复


    (由布赖恩·德·福伊提供)

    没有一种方法可以在后台运行代码,因此您不必等待代码完成,然后您的程序才能继续执行其他任务。进程管理取决于您的特定操作系统,其中许多技术都在使用中。

    几个 CPAN 模块可能会提供帮助,包括 IPC::Open2IPC::Open3IPC::RunParallel::JobsParallel::ForkManagerPOEProc::BackgroundWin32::Process。您可能会使用许多其他模块,因此请检查这些命名空间以获取其他选项。

    如果您使用的是类 Unix 系统,则可以通过在命令末尾添加 & 的系统调用来摆脱困境:

    system("cmd &")
    

    您也可以尝试使用 fork,如 perlfunc 中所述(尽管这与许多模块将为您做的事情相同)。

    STDIN、STDOUT 和 STDERR 是共享的

    主进程和后台进程(“子”进程)共享相同的 STDIN、STDOUT 和 STDERR 文件句柄。如果两者都尝试同时访问它们,可能会发生奇怪的事情。您可能想为孩子关闭或重新打开这些。您可以通过打开管道来解决此问题(请参阅在 perlfunc 中打开),但在某些系统上,这意味着子进程不能比父进程寿命长。 信号 您必须捕捉到 SIGCHLD 信号,也可能捕捉到 SIGPIPE。当后台进程完成时发送 SIGCHLD。当您写入子进程已关闭的文件句柄时会发送 SIGPIPE(未捕获的 SIGPIPE 可能会导致您的程序静默死亡)。这不是 system("cmd&") 的问题。

    僵尸

    您必须准备好在子进程完成时“收割”它。

    $SIG{CHLD} = sub { wait };
    
    $SIG{CHLD} = 'IGNORE';
    

    您也可以使用双叉。您立即为您的第一个孩子等待(),一旦它退出,初始化守护程序将为您的孙子等待()。

    unless ($pid = fork) {
        unless (fork) {
            exec "what you really wanna do";
            die "exec failed!";
        }
        exit 0;
    }
    waitpid($pid, 0);
    

    有关执行此操作的其他代码示例,请参阅 perlipc 中的信号。僵尸不是 system("prog &") 的问题。

    【讨论】:

      【解决方案3】:

      Perl 的system 函数有两种模式:

      1. 获取单个字符串并将其传递给命令外壳以允许处理特殊字符
      2. 获取字符串列表,执行第一个字符串并将其余字符串作为参数传递

      在第一种形式中,您必须小心转义可能对 shell 具有特殊含义的字符。第二种形式通常更安全,因为参数直接传递给正在执行的程序,而不涉及 shell。

      在您的情况下,您似乎混合了这两种形式。 & 字符如果传递给 shell,则仅具有“在后台启动此程序”的含义。在您的程序中,与号作为第 5 个参数传递给 xterm 命令。

      正如 Jakob Kruse 所说,简单的答案是使用 system 的单个字符串形式。如果任何参数来自不受信任的来源,您必须使用引用或转义来确保它们的安全。

      如果您更喜欢使用多参数形式,那么您需要调用fork(),然后可能使用exec() 而不是system()

      【讨论】:

      • tldr; system("./script.sh $arg1 &"); 而不是 system("./script.sh", "$arg1", "&");
      【解决方案4】:

      你试过了吗?

      system('xterm -geometry 80x25-5-5 -bg green &');
      

      http://www.rocketaware.com/perl/perlfaq8/How_do_I_start_a_process_in_the_.htm

      【讨论】:

        猜你喜欢
        • 2013-02-13
        • 1970-01-01
        • 2010-12-17
        • 1970-01-01
        • 2013-06-12
        • 1970-01-01
        • 2011-10-15
        • 1970-01-01
        • 2012-07-03
        相关资源
        最近更新 更多