6

我正在使用 wget 的 DOS 端口从 API 收集数据,以生成日志文件的数据(稍后将对其进行分析)。API 提供了我需要的所有信息,除了当前时间(它提供了数据流开始时的时间,但之后不再提供)。

API 最初通常提供 10 行数据,然后每 20-30 秒提供一行。

我正在尝试对该输出添加时间戳并将其复制到日志文件中 - 我不介意时间戳与输出的其余部分或之前的行位于同一行。

我首先从这个批处理文件开始:

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,"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 命令一直等到所有输入都接收完毕,然后疯狂地转储每一行。如果输入流足够大,您会在时间上得到轻微的变化,但没有什么能接近于原始命令生成每一行的时间。

这是一个混合 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) 中的键中执行此操作,因此它是默认设置。如果没有 Autorun 键,则创建它(它包含打开 cmd 提示符时执行的命令)
  2. 启动 cmd 提示符,然后将命令的输出通过管道传输到另一个cmd.exe,并将其输出重定向到文件:(
    more | cmd 2>nul >timestamped.log您将在我使用的地方使用您的命令more)。使用more, 输入:

这是一条带有
时间戳的消息 ^Z

在 timestamped.log 中生成以下行(在两行带有 cmd 处理器版本信息之后):

23:19:57,17_这是一条消息
23:19:59,95_带有时间戳

这是有效的,因为 cmd 将尝试执行您的日志条目。这失败了(并且错误消息被抑制/发送到 nul),但同时与提示(时间/日期)一起回显它。

如果您的日志消息没有被引用(或者更一般地说,如果您不确定它们的格式,或者它们不是在您的直接控制下创建的),您必须非常小心- 如果您的行恰好以一个单词开头有效命令 - 它将被执行!

于 2013-01-28T22:55:40.770 回答