【问题标题】:Invoke external shell script from PHP and get its process ID从 PHP 调用外部 shell 脚本并获取其进程 ID
【发布时间】:2009-09-24 10:47:28
【问题描述】:

如何从 PHP 本身调用外部 shell 脚本(或者外部 PHP 脚本)并在同一脚本中获取其进程 ID?

【问题讨论】:

    标签: php external-process


    【解决方案1】:
    $command =  'yourcommand' . ' > /dev/null 2>&1 & echo $!; ';
    
    $pid = exec($command, $output);
    
    var_dump($pid);
    

    【讨论】:

    • " > /dev/null 2>&1 & echo $!; "是什么意思
    • 它的意思是'将所有输出发送到空设备,这意味着所有输出都将在stdout中可用,并且echo $!简单地回显由脚本捕获的pid
    • 这也意味着该命令将在后台运行(如果您想要 pid,这将是您想要的),因此您的 php 脚本不会等待命令完成执行
    • 当它不等待命令完成时这是没用的,-1 来自我
    • 如果要等待命令完成 remove & as & 代表异步模式
    【解决方案2】:

    如果您想严格使用 PHP 提供的工具而不是 Unix-specific wizardry 来执行此操作,您可以使用 proc_openproc_get_status 执行此操作,尽管需要将描述符规范传递给 proc_open 会让人不愉快详细使用:

    <?php
    
    $descriptorspec = [
        0 => ['pipe', 'r'],
        1 => ['pipe', 'w'],
        2 => ['pipe', 'w']
    ];
    $proc = proc_open('yourcommand', $descriptorspec, $pipes);
    $proc_details = proc_get_status($proc);
    $pid = $proc_details['pid'];
    
    echo $pid;
    

    【讨论】:

    • 如何获得输出?
    • $pipes 将填充一个数组,其中包含$descriptorspec 中每个管道的资源。所以你需要从文件描述符$pipes[1] 中读取标准输出。
    【解决方案3】:

    如需跨平台解决方案,请查看symfony/process

    use Symfony\Component\Process\Process;
    $process = new Process('sleep 100');
    $process->start();
    var_dump($process->getPid());
    

    使用 composer (composer require symfony/process) 安装 symfony/process 后,您可能需要使用 composer dump-autoload 更新自动加载信息,然后使用 require __DIR__ . '/vendor/autoload.php'; 要求自动加载。

    还请注意,您只能获取 正在运行的 进程的 PID。 API 详情请参考the documentation

    【讨论】:

      【解决方案4】:

      最终为我工作的是使用pgrep 获取在 PHP 中调用 exec() 后执行的命令(或进程名称)的 PI​​D。

      exec($command);
      $pid = exec("pgrep $command");
      

      这也适用于启动后台进程。但是,您必须记住将程序的输出通过管道传输到/dev/null,否则 PHP 将挂起。此外,在调用pgrep 时,您不能包含命令的管道部分:

      $command = "bg_process -o someOption";
      exec($command + " > /dev/null &"); //Separate the pipe and '&' from the command
      $pid = exec("pgrep $command");
      

      请注意,如果系统有多个使用相同命令启动的进程,它将返回与pgrep 给出的命令匹配的所有进程的 PID。如果只传入一个进程名,它将返回所有具有该进程名的 PID。

      【讨论】:

      • 由于您概述的原因,这比此处给出的其他解决方案更脆弱(如果您使用相同的命令字符串调用多个进程,这不会让您知道哪个是您刚刚的已启动)并且并没有真正提供任何优势来弥补它。
      猜你喜欢
      • 1970-01-01
      • 2014-11-12
      • 2015-10-12
      • 2018-10-14
      • 1970-01-01
      • 2011-11-28
      • 2011-09-20
      • 1970-01-01
      • 2020-12-14
      相关资源
      最近更新 更多