如何随时从 Windows 中的命令提示符捕获显示输出?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/11911045/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to capture display output from a command prompt in Windows at any moment?
提问by AdamC
I'm tring to capture de information shown in a command prompt (cmd window) at a specific moment and send it to a text file.
我正在尝试在特定时刻捕获命令提示符(cmd 窗口)中显示的信息并将其发送到文本文件。
I have an app in C/C++ that is launched by a batch script like this:
我有一个 C/C++ 应用程序,它由这样的批处理脚本启动:
c:\myProgramInC.exe
echo "Ending with error"
PAUSE
myProgramInC.exe is always running (with an infinite loop) so if my script gets to the echo command it means my app ended with an abend.
myProgramInC.exe 始终在运行(无限循环),因此如果我的脚本进入 echo 命令,则意味着我的应用程序以异常结束结束。
What I want to get is the previous lines before the end execution of the script since my myProgramInC.exe always prints info about what is going on and it would be very useful to see what it was happening when the error ocurred. Something like this
我想得到的是脚本结束执行之前的前几行,因为我的 myProgramInC.exe 总是打印有关正在发生的事情的信息,并且在发生错误时查看正在发生的事情非常有用。像这样的东西
c:\myProgramInC.exe
**** Execution of process to get te previous N lines in the command prompt ****
echo "Ending with error"
PAUSE
I know the cmd window have a buffer and I've been thinking to capture all of this data from such buffer. It is any way to get this info as text to store it in a file?
我知道 cmd 窗口有一个缓冲区,我一直在考虑从这样的缓冲区中捕获所有这些数据。有什么方法可以将此信息作为文本存储在文件中?
I'v been trying with something more professional shuch as to make a dump of the memory with ProcDump but since I have various myProgramInC.exe running at the same time (each one stored in a different location) I just get the message "Multiple processes match the specified name." and the rest of the options are just not useful for me since my app doesn't get unresponsive, it simply ends.
我一直在尝试使用更专业的方法来使用 ProcDump 进行内存转储,但是由于我同时运行了多个 myProgramInC.exe(每个都存储在不同的位置),我只收到消息“多个进程匹配指定的名称。” 其余的选项对我来说没有用,因为我的应用程序不会无响应,它只是结束。
Any ideas?
有任何想法吗?
采纳答案by Harry Johnston
You can do this in C easily enough, using the ReadConsoleOutputCharacterfunction.
您可以使用ReadConsoleOutputCharacter函数在 C 中轻松完成此操作。
回答by wmz
Quick trick would be to execute in context of for /f
, you do not even need a batch file for that, you could execute directly from cmd line:for /f "tokens=*" %F in ('c:\myProgramInC.exe') do @echo %F >>myPrograminC.log
快速技巧是在 的上下文中执行for /f
,您甚至不需要批处理文件,您可以直接从 cmd 行执行:for /f "tokens=*" %F in ('c:\myProgramInC.exe') do @echo %F >>myPrograminC.log
This will suppress all output until your program abends and only then would write all messages to file. If your app writes log messages infrequently (or fails quickly :-)) it should work. I tested it with 10 000 lines.
这将抑制所有输出,直到您的程序异常终止,然后才会将所有消息写入文件。如果您的应用程序很少写入日志消息(或很快失败:-))它应该可以工作。我用 10 000 行测试了它。
Batch code below is based on same idea - please note that even it writes only 5 last lines, it still has to scan through all of themso I'm not sure it's any better than above 1 liner.
下面的批处理代码基于相同的想法 - 请注意,即使它只写了最后 5 行,它仍然必须扫描所有这些行,所以我不确定它是否比 1 行以上更好。
@echo off
setlocal
for /f "tokens=*" %%P in ('c:\myProgramInC.exe') do (
for /L %%C in (4,-1,1) do (
set /A next=%%C+1
call set line_%%next%%=%%line_%%C%%
)
set line_1=%%P
)
echo program ended abnormally! %date% %time%
for /L %%C in (5,-1,1) do call echo %%line_%%C%%
回答by aphoria
Ok, there may be a more elegant way to do this, but this will work assuming you have PowerShell.
好的,可能有更优雅的方法来做到这一点,但假设您有 PowerShell,这将起作用。
Create a PowerShell script file called Get-ConsoleAsText.ps1
that contains the script below. Note, I did not create this script. I found it at Windows PowerShell Blog - Capture console screen.
创建一个名为的 PowerShell 脚本文件Get-ConsoleAsText.ps1
,其中包含以下脚本。注意,我没有创建这个脚本。我在Windows PowerShell 博客 - 捕获控制台屏幕上找到了它。
#################################################################################################################
# Get-ConsoleAsText.ps1
#
# The script captures console screen buffer up to the current cursor position and returns it in plain text format.
#
# Returns: ASCII-encoded string.
#
# Example:
#
# $textFileName = "$env:temp\ConsoleBuffer.txt"
# .\Get-ConsoleAsText | out-file $textFileName -encoding ascii
# $null = [System.Diagnostics.Process]::Start("$textFileName")
#
# Check the host name and exit if the host is not the Windows PowerShell console host.
if ($host.Name -ne 'ConsoleHost')
{
write-host -ForegroundColor Red "This script runs only in the console host. You cannot run this script in $($host.Name)."
exit -1
}
# Initialize string builder.
$textBuilder = new-object system.text.stringbuilder
# Grab the console screen buffer contents using the Host console API.
$bufferWidth = $host.ui.rawui.BufferSize.Width
$bufferHeight = $host.ui.rawui.CursorPosition.Y
$rec = new-object System.Management.Automation.Host.Rectangle 0, 0, ($bufferWidth), $bufferHeight
$buffer = $host.ui.rawui.GetBufferContents($rec)
# Iterate through the lines in the console buffer.
for($i = 0; $i -lt $bufferHeight; $i++)
{
for($j = 0; $j -lt $bufferWidth; $j++)
{
$cell = $buffer[$i, $j]
$null = $textBuilder.Append($cell.Character)
}
$null = $textBuilder.Append("`r`n")
}
return $textBuilder.ToString()
If you call the PowerShell script by itself, it will read the console buffer and write it back to the screen
如果你自己调用 PowerShell 脚本,它会读取控制台缓冲区并将其写回屏幕
PowerShell -noprofile -sta -command "C:\Scripts\Get-ConsoleAsText.ps1"
You can also call it like this to capture the contents to a file:
您也可以这样调用它以将内容捕获到文件中:
PowerShell -noprofile -sta -command "C:\Scripts\Get-ConsoleAsText.ps1 | Out-File MyOutput.txt -encoding ascii"
If you want to process it and perform some action within the batch file, you can call it and process the output using a FOR
command. I will leave that exercise to you.
如果要处理它并在批处理文件中执行某些操作,可以调用它并使用FOR
命令处理输出。我会把那个练习留给你。
So, for example, your batch file would look like this to capture the console output to a file:
因此,例如,您的批处理文件将如下所示以将控制台输出捕获到文件中:
c:\myProgramInC.exe
echo "Ending with error"
PowerShell -noprofile -sta -command "C:\Scripts\Get-ConsoleAsText.ps1 | Out-File MyOutput.txt -encoding ascii"
PAUSE
回答by AdamC
Finally this is what I get to make it work. Following the advise of Harry Johnston I searched about the way ReadConsoleOutputCharacter function works and I got the next program running.
最后,这就是我让它工作的方法。按照 Harry Johnston 的建议,我搜索了 ReadConsoleOutputCharacter 函数的工作方式,并运行了下一个程序。
#include "stdafx.h"
#include <iostream>
#include <windows.h>
#include <fstream>
#define BUFFER_SIZE 50000
int main(){
HANDLE hOut;
COORD location = {0, 0};
char *buffer=NULL;
DWORD numberRead;
std::ofstream fileLog;
buffer = new TCHAR[BUFFER_SIZE];
if ( buffer==NULL )
{
printf("\nError: memory could not be allocated.\n");
return 1;
}
fileLog.open ("logger.txt");
if ( fileLog.fail() )
{
printf("\nError: file could not be opened.\n");
return 1;
}
hOut = GetStdHandle(STD_OUTPUT_HANDLE);
ReadConsoleOutputCharacter(hOut, buffer, BUFFER_SIZE, location, &numberRead);
fileLog << buffer ;
free(buffer);
fileLog.close();
return 0;
}
Much of the code I found it in internet and right now I don't have the URL (besides it's from another forum site and I don't know if it's OK to make references to competitor sites) but with a single search in google wouldn't be difficult to find it.
我在互联网上找到的大部分代码现在我没有 URL(除了它来自另一个论坛站点,我不知道是否可以引用竞争对手的站点)但是在 google 中进行一次搜索不会不难找到。
I added the part where it writes to a file and allocation of memory. It run's perfectly in VS C++ 6.
我添加了它写入文件和内存分配的部分。它在 VS C++ 6 中完美运行。
This works fine for me although could be better. Two things aren't very nice like
这对我来说很好,虽然可能会更好。两件事不太好,比如
- It writes all the content from the buffer to a file but it doesn't keep the newlines so I get a text file with all the information in ONE single line.
- Can not be defined how much lines to be captured. It just takes everything from the beginnig of the buffer to the point where the program starts, wich is not bad but since this app should run in different servers where each one has a different buffer for each set of command prompt windows, is not much efficient just to use a buffer of 50000 bytes when in some cases the buffer is smaller. I think that could be a lot but since it is allocated in real time maybe is not so wrong to use as much memory.
- 它将缓冲区中的所有内容写入文件,但不保留换行符,因此我得到一个文本文件,其中包含一行中的所有信息。
- 无法定义要捕获多少行。它只需要从缓冲区的开始到程序启动的所有内容,这还不错,但是由于此应用程序应该在不同的服务器上运行,其中每个服务器对每组命令提示符窗口都有不同的缓冲区,因此效率不高只是在某些情况下缓冲区较小时使用 50000 字节的缓冲区。我认为这可能很多,但由于它是实时分配的,因此使用尽可能多的内存可能并没有错。
回答by Micheal Espinola
If any error messages are going to be reported back to the command output stream, it can be easily redirected via Redirection Operators for STDOUT (Standard Output) and STDERR (Standard Errors). Depending on whether or not you want to capture output and/or errors, is up to you. More than likely, you are looking for something like:
如果将任何错误消息报告回命令输出流,则可以通过 STDOUT(标准输出)和 STDERR(标准错误)的重定向运算符轻松重定向。取决于您是否要捕获输出和/或错误,取决于您。更有可能的是,您正在寻找类似的东西:
- command 2>> filename
- 命令 2>> 文件名
The "2" is a part of the redirection operator, and indicates that STDERR will be redirected and appended to filename.
“2”是重定向操作符的一部分,表示 STDERR 将被重定向并附加到文件名。
Sources, examples, and documentation:
来源、示例和文档:
回答by artapet
One thing that comes in minde immediately is redirecting output of your command line to to a file:
立即想到的一件事是将命令行的输出重定向到文件:
c:\myProgramInC.exe >> myProgramInC.log
then you can see what is in log file.
然后您可以看到日志文件中的内容。