有没有办法,比如Perl或PHP,我可以从另一个输出到Windows cmd shell的进程中获取输出?我有一个输出某些信息的游戏服务器,比如说“玩家完成了43s的跟踪”,我想抓住那条线并使用Perl或PHP向网络服务器发送请求以更新网页上的排名。有没有办法在Perl或PHP中获取输出管道?或者我可以使用C ++ Windows API实现这一点吗?
我在这里澄清一下:我想执行一个单独的Perl或PHP脚本来抓取Windows cmd shell的输出,并且显示给Windows cmd shell的输出来自不同的进程。
答案 0 :(得分:4)
您可以使用IPC::Open3从其他进程的标准输出中读取。请注意,进程间通信假定进程之间存在父/子关系。如果不是这样的话......我不知道附加到预先存在的进程的输出的机制。在这种情况下,您可能需要更改生产者以将数据写入应用程序可以读取的日志文件(或数据库)。
答案 1 :(得分:3)
如果你关心的只是STDOUT,你可以使用IPC::Open2中的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";
}
答案 2 :(得分: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.
答案 3 :(得分:1)
答案 4 :(得分:1)
此代码将控制台应用程序的STDOUT重定向到字符串列表,您可以在备忘录中使用该字符串列表。它是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}
答案 5 :(得分: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()方法逐个发出命令,这样您也可以处理返回和任何异常。