6

wgetのDOSポートを使用してAPIからデータを収集し、ログファイルのデータを生成しています(これは後日分析されます)。APIは、現在の時刻を除いて、必要なすべての情報を提供します(データのストリームの開始時の時刻を提供しますが、その後は提供しません)。

APIは、通常、最初に10行のデータを提供し、その後20〜30秒ごとに1行を提供します。

この出力にタイムスタンプを付けてログファイルにコピーしようとしています-タイムスタンプが出力の残りの行と同じ行にあるか、前の行にあるかは関係ありません。

私は最初にこのバッチファイルから始めました:

addtimes.bat:

@echo off >nul
:start
set /p input="":

echo %time% 
echo %input%

goto:start

(「wget ..... | addtimes.bat> log.log」と呼ばれます)

ただし、これによりデータが削除され、多くのデータ行の先頭が失われました。

ここを見て、forループを使用する必要があることに気付きました。

addtimes2.bat:

@echo off
cls
setlocal EnableDelayedExpansion
for /F "tokens=*" %%a in ('more') do ( 
echo !time! %%a )
)

遅延拡張を有効にする場合と有効にしない場合で試しました。

異なるタイムスタンプで一度に1行ずつ情報を渡すことができないようです。データストリームを閉じると、すべての行が同じタイムスタンプを取得します。

一般的な入力データの形式は次のとおりです。

[1,"219","265",14528,1359031137000,1359031137000]
[1,"6594","358",18188,1359031019000,1359031019000]
[1,"690","94",15920,1359031534000,1359031534000]
[1,"25164","102",2129,1359031457000,1359031457000]


[1,"3488","329",2109,1359030868000,1359030868000]

[1,"37247","6",11506,1359031223000,1359031223000]

データにUTC時刻があることに気付くかもしれませんが、それらは現在の時刻ではありません。

4

2 に答える 2

4

純粋なネイティブバッチを使用して、希望する結果が得られるとは思いません。すべての時間が同じである理由は、入力ストリーム全体がバッファリングされるまで(パイプの左側のコマンドが終了するまで)、FOR/Fループは入力の行を処理しないためです。FOR / Fコマンドは、すべての入力が受信されるまで待機してから、1回のマッドラッシュですべての行をダンプします。入力ストリームが十分に大きい場合、時間にわずかな変動が生じますが、元のコマンドが各行をいつ生成したかを表すことに近いものはありません。

これがあなたが望むことをするハイブリッドJScript/バッチスクリプトです。ストレートJScriptファイルとしては正常に機能しますが、CSCRIPTを明示的に使用する必要があります。ハイブリッドアプローチは、ユーティリティをより便利にします。

これをaddtimes.batと呼び、以前と同じように使用します。

@if (@X)==(@Y) @end /* Harmless hybrid line that begins a JScript comment

::************ Batch portion ***********
@echo off
cscript //E:JScript //nologo "%~f0"
exit /b 0

************* JScript portion **********/
while (!WScript.StdIn.AtEndOfStream) {
  var ts = new Date()
  var ms = (ts.getTime() % 1000)
  WScript.Stdout.WriteLine(
    ts.getFullYear() + "-" +
    ((ts.getMonth()<9)?"0":"") + (ts.getMonth()+1) + "-" +
    ((ts.getDate()<10)?"0":"") + ts.getDate() + " " +
    ((ts.getHours()<10)?"0":"") + ts.getHours() + ":" +
    ((ts.getMinutes()<10)?"0":"") + ts.getMinutes() + ":" +
    ((ts.getSeconds()<10)?"0":"") + ts.getSeconds() + "." +
    ((ms<10)?"00":((ms<100)?"0":"")) + ms + " - " +
    WScript.StdIn.ReadLine()
  );
}


編集

wmzには非常に賢く危険な解決策があります。その解決策は単純化することができます-Autorunをいじくり回す必要はありません。

警告 -wmzが言ったように、出力のいずれかの行が実行可能コマンドまたはプログラム名で始まる場合、以下の解決策は非常に悪い結果をもたらす可能性があります!このソリューションを実際に使用することはお勧めしませんが、非常に興味深いと思います。

(echo @prompt $D $T -$S & YourCommandHere )|cmd 2>nul|findstr /rbc:"../../.... ..:..:..\... - " >log.log

FINDSTRパイプは、CMDヘッダー情報、最初のPROMPTコマンド、およびCMDが各「コマンド」の後に挿入する不要な空白行を取り除くために追加されます。FINDSTR正規表現は、選択したプロンプトとロケールの詳細に一致するように変更する必要がある場合があります。

于 2013-01-28T20:10:54.237 に答える
3

注意してください:これは多くの副作用をもたらす可能性があり(またはまったく機能しないか、システムを不安定にするなど)、テストされていません。それは何よりもバッチでの運動です

編集:このアイデアを使用する洗練された方法については、debenhamの回答を参照してください。

  1. プロンプトを時刻(prompt $T)または必要に応じて日時に設定します(prompt $D $T)。Autorunレジストリ()のキーでそれを行う必要があるHKEY_CURRENT_USER\software\Microsoft\Command Processorので、デフォルトです。自動実行キーがない場合は、作成します(cmdプロンプトを開いたときに実行されるコマンドが含まれています)
  2. cmdプロンプトを起動し、コマンドの出力を別のにパイプし、cmd.exeその出力をファイルにリダイレクトします:(
    more | cmd 2>nul >timestamped.log私が使用したコマンドを使用しますmore)。でmore、次のように入力します。


これはタイムスタンプが付けられたメッセージです^Z

timestamped.logに次の行を生成します(cmdプロセッサのバージョン情報を含む2行の後):

23:19:57,17_これはメッセージです
23:19:59,95_タイムスタンプが付けられました

cmdがログエントリを実行しようとするため、これは機能します。これは失敗します(そしてエラーメッセージは抑制/nulに送信されます)が、同時にプロンプ​​ト(時刻/日付)と一緒にエコーします。

ログメッセージが引用符で囲まれていない場合(または、より一般的には、形式がわからない場合、または直接制御して作成されていない場合)、行がたまたま次の単語で始まっている場合は、十分に注意する必要があります。有効なコマンド-実行されます!

于 2013-01-28T22:55:40.770 に答える