2009-06-16 75 views
1

Perl或PHP有什么方法可以从另一个输出到Windows cmd shell的进程获取输出吗?我有一个输出某些信息的游戏服务器,例如说'玩家完成了43s的轨道',我想抓住这条线并使用Perl或PHP向网络服务器发送请求以更新网页上的排名。有没有办法在Perl或PHP中抓取输出管道?或者我可以实现这一点使用C + + Windows API也许?如何捕获Windows cmd shell的输出?

让我在这里澄清一下:我想执行一个独立的Perl或PHP脚本,它抓取Windows cmd shell的输出,并且显示给Windows cmd shell的输出来自不同的进程。

回答

2

您需要Perl中启动服务器:

my $server_out = `server.exe`; # Note the backticks. 

现在$ server_out包含SERVER.EXE的输出。但这里的诀窍是,你必须等到server.exe退出才能完成。

尝试IPC::Run(这不是一个核心模块)

use English; 
use IPC::Run; 
my ($stdout, $stderr); 

IPC::Run::run([$cmd, $arg1, $arg2, $argN], \undef, \$stdout, $stderr); 

while(<$stdout>) { 
    print "Cmd said $_\n"; 
} 

注:代码未经测试。

实测值的信息here.

1

捕捉Perl的输出是一样简单:

$output = qx(command); 

$output = `command`; # backticks 

参见:perldoc perlop

+0

这是行不通的,因为一旦命令完成我只能访问到$输出...和服务器过程中没有“完成” – user105033 2009-06-16 16:46:26

4

你可以使用IPC::Open3从另一个进程的标准输出读。请注意,进程间通信假定进程之间有父/子关系。如果情况并非如此......我不知道有一种机制可以附加到已有流程的输出中。在这种情况下,您可能需要更改生产者以将数据写入日志文件(或数据库),以便应用程序可以读取。

3

如果所有你关心的是STDOUT,你可以只使用open2从IPC::Open2

#!/usr/bin/perl 

use strict; 
use warnings; 

use IPC::Open2; 

#if there are arguments pretend to be the server 
#for this example 
if (@ARGV) { 
    local $| = 1; 
    for my $i (1 .. 100) { 
     print "pid $$ iter $i\n"; 
     sleep 1; 
    } 
    exit; 
}   

#run perl with the current script as its argument, 
#pass in an arg so that we trigger the behaviour 
#above 
open2 my $out, my $in, $^X, $0, 1 
    or die "could not run '$^X $0 1': $!\n"; 

while (<$out>) { 
    s/[\r\n]//g; 
    print "pid $$ saw [$_]\n"; 
} 
+0

,当我回家 – user105033 2009-06-16 18:07:18

+0

我给这个一展身手 - |在Windows下无法使用。 – 2009-06-16 20:36:11

1

此代码重定向控制台应用程序的StringList的,你可以在例如备忘录使用的标准输出。这是Delphi代码,但在C++中,基本思想完全相同。

我使用它来隐藏运行控制台应用程序,同时将输出重定向到我自己的应用程序,以显示在窗格中。一旦数据进入,它就会向AStrings添加一条新线,因此您可以在完成之前访问其他应用程序的输出。

procedure RunConsoleApp(const CommandLine: string; AStrings: TStrings); 
type 
    TCharBuffer = array[0..MaxInt div SizeOf(Char) - 1] of Char; 
const 
    MaxBufSize = 1024; 
var 
    I: Longword; 
    SI: TStartupInfo; 
    PI: TProcessInformation; 
    SA: PSecurityAttributes; 
    SD: PSECURITY_DESCRIPTOR; 
    NewStdIn: THandle; 
    NewStdOut: THandle; 
    ReadStdOut: THandle; 
    WriteStdIn: THandle; 
    Buffer: ^TCharBuffer; 
    BufferSize: Cardinal; 
    Last: WideString; 
    Str: WideString; 
    ExitCode_: DWORD; 
    Bread: DWORD; 
    Avail: DWORD; 
begin 
    GetMem(SA, SizeOf(TSecurityAttributes)); 

    case Win32Platform of 
    VER_PLATFORM_WIN32_NT: 
     begin 
     GetMem(SD, SizeOf(SECURITY_DESCRIPTOR)); 
     SysUtils.Win32Check(InitializeSecurityDescriptor(SD, SECURITY_DESCRIPTOR_REVISION)); 
     SysUtils.Win32Check(SetSecurityDescriptorDacl(SD, True, nil, False)); 
     SA.lpSecurityDescriptor := SD; 
     end; {end VER_PLATFORM_WIN32_NT} 
    else 
    SA.lpSecurityDescriptor := nil; 
    end; {end case} 

    SA.nLength := SizeOf(SECURITY_ATTRIBUTES); 
    SA.bInheritHandle := True; 

    SysUtils.Win32Check(CreatePipe(NewStdIn, WriteStdIn, SA, 0)); 

    if not CreatePipe(ReadStdOut, NewStdOut, SA, 0) then 
    begin 
    CloseHandle(NewStdIn); 
    CloseHandle(WriteStdIn); 
    SysUtils.RaiseLastWin32Error; 
    end; {end if} 

    GetStartupInfo(SI); 
    SI.dwFlags := STARTF_USESTDHANDLES or STARTF_USESHOWWINDOW; 
    SI.wShowWindow := {SW_SHOWNORMAL} SW_HIDE; 
    SI.hStdOutput := NewStdOut; 
    SI.hStdError := NewStdOut; 
    SI.hStdInput := NewStdIn; 

    if not CreateProcess(nil, PChar(CommandLine), nil, nil, True, CREATE_NEW_CONSOLE, nil, nil, SI, PI) then 
    begin 
    CloseHandle(NewStdIn); 
    CloseHandle(NewStdOut); 
    CloseHandle(ReadStdOut); 
    CloseHandle(WriteStdIn); 
    SysUtils.RaiseLastWin32Error; 
    end; {end if} 

    Last := ''; 
    BufferSize := MaxBufSize; 
    Buffer := AllocMem(BufferSize); 

    try 
    repeat 
     SysUtils.Win32Check(GetExitCodeProcess(PI.hProcess, ExitCode_)); 
     PeekNamedPipe(ReadStdOut, Buffer, BufferSize, @Bread, @Avail, nil); 

     if (Bread <> 0) then 
     begin 
     if (BufferSize < Avail) then 
     begin 
      BufferSize := Avail; 
      ReallocMem(Buffer, BufferSize); 
     end; {end if} 
     FillChar(Buffer^, BufferSize, #0); 
     Windows.ReadFile(ReadStdOut, Buffer^, BufferSize, Bread, nil); 
     Str := Last; 
     I := 0; 

     while (I < Bread) do 
     begin 

      case Buffer^[I] of 
      #0: inc(I); 
      #7: begin 
        inc(I); 
        Windows.Beep(800, 50); 
        Str := Str + '^'; 
       end; 
      #10: 
       begin 
       inc(I); 
       AStrings.Add(Str); 
       Str := ''; 
       end; {end #10} 
      #13: 
       begin 
       inc(I); 
       if (I < Bread) and (Buffer^[I] = #10) then 
        inc(I); 
       AStrings.Add(Str); 
       Str := ''; 
       end; {end #13} 
      else 
      begin 
       Str := Str + Buffer^[I]; 
       inc(I); 
      end; {end else} 
      end; {end case} 
     end; {end while} 
     Last := Str; 
     end; {end if} 
     Sleep(1); 
     Application.ProcessMessages; 

    until (ExitCode_ <> STILL_ACTIVE); 

    if Last <> '' then 
     AStrings.Add(Last); 

    finally 
    FreeMem(Buffer); 
    end; {end try/finally} 

    CloseHandle(PI.hThread); 
    CloseHandle(PI.hProcess); 
    CloseHandle(NewStdIn); 
    CloseHandle(NewStdOut); 
    CloseHandle(ReadStdOut); 
    CloseHandle(WriteStdIn); 

end; {end procedure} 
0

这里是一个PHP特定的解决方案,该项目允许PHP获得和动态与真实的CMD端子交互。在这里获得:https://github.com/merlinthemagic/MTS

下载您只需使用下面的代码后:

//if you prefer Powershell, replace 'cmd' with 'powershell' 
$shellObj = \MTS\Factories::getDevices()->getLocalHost()->getShell('cmd'); 

$strCmd1 = 'some_app.exe -param "test"'; 
$return1 = $shellObj->exeCmd($strCmd1); 

返回会给你从CMD命令返回或错误,就如同您坐在控制台。此外,您可以针对$ shellObj发出任何您喜欢的命令,该环境在PHP脚本的整个生命周期内都会维护。因此,不要将脚本文件绑定到脚本文件中,只需使用exeCmd()方法逐个发布它们,这样您还可以处理返回和任何异常。