2

特定の瞬間にコマンドプロンプト(cmdウィンドウ)に表示される情報をキャプチャして、テキストファイルに送信しようとしています。

次のようなバッチスクリプトによって起動されるC/C++のアプリがあります。

c:\myProgramInC.exe
echo "Ending with error"
PAUSE

myProgramInC.exeは常に(無限ループで)実行されているため、スクリプトがechoコマンドに到達した場合、アプリは異常終了で終了したことを意味します。

myProgramInC.exeは常に何が起こっているかに関する情報を出力するため、スクリプトの実行が終了する前の前の行を取得したいので、エラーが発生したときに何が起こっていたかを確認すると非常に便利です。このようなもの

c:\myProgramInC.exe
**** Execution of process to get te previous N lines in the command prompt ****
echo "Ending with error"
PAUSE

私はcmdウィンドウにバッファーがあることを知っており、そのようなバッファーからこのすべてのデータをキャプチャすることを考えていました。この情報をテキストとして取得してファイルに保存する方法はありますか?

ProcDumpでメモリのダンプを作成するなど、より専門的な方法で試していますが、さまざまなmyProgramInC.exeを同時に実行しているため(それぞれが異なる場所に保存されています)、「複数のプロセス」というメッセージが表示されます。指定された名前と一致します。」そして、残りのオプションは、私のアプリが応答しなくなることはなく、単に終了するだけなので、私には役に立ちません。

何か案は?

4

6 に答える 6

2

簡単なトリックは、のコンテキストで実行することfor /fです。そのためのバッチファイルも必要ありません。コマンド行から直接実行できます。
for /f "tokens=*" %F in ('c:\myProgramInC.exe') do @echo %F >>myPrograminC.log

これにより、プログラムが異常終了するまですべての出力が抑制され、その後、すべてのメッセージがファイルに書き込まれます。アプリがログメッセージを頻繁に書き込まない(またはすぐに失敗する:-))場合は、機能するはずです。10000行でテストしました。

以下のバッチコードは同じ考えに基づいています-最後の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%% 
于 2012-08-11T22:35:50.670 に答える
2

これを行うためのより洗練された方法があるかもしれませんが、PowerShellを使用している場合はこれで機能します。

以下のスクリプトを含むPowerShellスクリプトファイルを作成しGet-ConsoleAsText.ps1ます。、私はこのスクリプトを作成しませんでした。WindowsPowerShellブログ-キャプチャコンソール画面で見つけました。

#################################################################################################################
# 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()

PowerShellスクリプトを単独で呼び出すと、コンソールバッファーが読み取られ、画面に書き戻されます。

PowerShell -noprofile -sta -command "C:\Scripts\Get-ConsoleAsText.ps1"

次のように呼び出して、コンテンツをファイルにキャプチャすることもできます。

PowerShell -noprofile -sta -command "C:\Scripts\Get-ConsoleAsText.ps1 | Out-File MyOutput.txt -encoding ascii"

それを処理してバッチファイル内で何らかのアクションを実行する場合は、それを呼び出してコマンドを使用して出力を処理できますFOR。その演習はあなたにお任せします。

したがって、たとえば、バッチファイルは、コンソール出力をファイルにキャプチャするために次のようになります。

c:\myProgramInC.exe
echo "Ending with error"
PowerShell -noprofile -sta -command "C:\Scripts\Get-ConsoleAsText.ps1 | Out-File MyOutput.txt -encoding ascii"
PAUSE
于 2012-08-14T15:09:30.387 に答える
1

最後に、これは私がそれを機能させるために得るものです。ハリー・ジョンストンのアドバイスに従って、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;
}

インターネットで見つけたコードの多くは、現在URLを持っていません(別のフォーラムサイトからのものであり、競合他社のサイトを参照してもよいかどうかはわかりません)が、Googleで1回検索するとそれを見つけるのは難しいことではありません。

ファイルに書き込む部分とメモリの割り当てを追加しました。VS C++6で完全に動作します。

これは私にとってはうまくいきますが、もっと良いかもしれません。2つのことはあまり良くありません

  1. バッファからすべてのコンテンツをファイルに書き込みますが、改行を保持しないため、すべての情報を1行にまとめたテキストファイルを取得します。
  2. キャプチャする行数を定義できません。バッファの開始からプログラムの開始まですべてが必要ですが、悪くはありませんが、このアプリはコマンドプロンプトウィンドウのセットごとに異なるバッファを持つ異なるサーバーで実行する必要があるため、あまり効率的ではありません場合によってはバッファが小さい場合に、50000バイトのバッファを使用するだけです。かなりの量になると思いますが、リアルタイムで割り当てられるので、多くのメモリを使用するのはそれほど間違いではないかもしれません。
于 2012-08-14T22:20:16.470 に答える
1

ReadConsoleOutputCharacter関数を使用すると、Cでこれを簡単に行うことができます。

于 2012-08-11T09:09:51.070 に答える
1

エラーメッセージがコマンド出力ストリームに報告される場合は、STDOUT(標準出力)およびSTDERR(標準エラー)のリダイレクト演算子を使用して簡単にリダイレクトできます。出力やエラーをキャプチャするかどうかに応じて、あなた次第です。おそらく、あなたは次のようなものを探しています:

  • コマンド2>>ファイル名

「2」はリダイレクト演算子の一部であり、STDERRがリダイレクトされてファイル名に追加されることを示します。

ソース、例、およびドキュメント:

  1. http://www.microsoft.com/resources/documentation/windows/xp/all/proddocs/en-us/redirection.mspx
  2. http://ss64.com/nt/syntax-redirection.html
于 2013-07-29T06:44:11.487 に答える
0

すぐに頭に浮かぶことの1つは、コマンドラインの出力をファイルにリダイレクトすることです。

c:\myProgramInC.exe >> myProgramInC.log

次に、ログファイルの内容を確認できます。

于 2012-08-11T01:48:48.033 に答える