Windows批处理 - 如何在将stdout重定向到文件时添加时间戳

4

我正在执行make all -d --trace

如何让Gnu Make输出每行的时间戳?

更一般地说,如何在每个STDOUT和STDERR语句中添加时间戳?

Linux/Bash有一个解决方案,但我在Windows上。

我创建了一个一行的批处理文件add_ts.bat: echo %time% %1

我尝试了以下命令,但只得到了一个时间戳(没有输出的行):

make all --trace -d 2>&1 | add_ts.bat

2个回答

3

大致上,您需要一个类似于批处理文件的东西:

add_ts.bat

@for /F "usebackq delims==" %%i in (`%1`) do @echo %time% %%i

你要运行的命令是:

add_ts.bat "make all -d --trace" > buildlog.txt

然而,如果您想捕获和记录由传递给%1的命令产生的STDOUT以及STDERR的时间戳,仅使用反引号操作符无法满足要求,因为此操作符仅捕获STDOUT
为了解决这个问题,您需要在反引号内部捕获STDERRSTDOUT,并使用重定向来实现。这意味着您需要运行一个子shell来理解重定向,同时需要转义重定向运算符,以防止它们被顶层shell解释。总的来说,需要执行以下操作:
@for /F "usebackq delims==" %%i in (`cmd /C %1 2^>^&1`) do @echo %time% %%i 

按同样的方式运行。

后来

我不明白的是,为什么|本身不足以将STDOUT和STDERR发送到add_ts.bat的STDIN

是的。我认为您存在两个误解的组合。

:您认为程序的命令行参数与其标准输入相同,或者它从其标准输入获取命令行参数。它不是这样的。 如果有的话,程序的命令行参数将作为程序启动协议中的固定字符串列表传递给它。它的标准输入是一个输入流,由操作系统在程序启动时同时提供,并默认连接到控制台。可以通过重定向运算符在shell中覆盖此默认值。该输入流的内容事先并不固定。只要程序正在运行,并且程序读取它时,它将向程序提供控制台输入或其重定向代理输入的任何内容。程序可以解析或忽略其命令行参数,并且完全独立于此,它可以读取或忽略其标准输入。

你的程序 add_ts.bat 是一个解析其命令行参数的程序,它使用 %1 并忽略其他所有输入。同时它完全忽略了标准输入。 第二点:你相信管道的效果,例如:
a | b

目的是启动一个 a 进程,然后对于每一行写入标准输出,都会启动一个独立的 b 进程,并将由 a 写入的一行作为单个命令行参数(不管该行有多少个单词),自动发送给该进程并用其执行相应操作。

然而实际运行情况并非如此。操作系统只会启动一个 a 进程和一个 b 进程,并将前者的标准输出连接到后者的标准输入。为了使管道正常工作,b 必须是一个能够读取其标准输入的程序,而你的 add_ts.bat 并非如此。它只是一个解析其第一个命令行参数的程序:由于 | 不会提供任何参数,所以该命令行:

make all --trace -d 2>&1 | add_ts.bat

它也没有给出任何命令行。命令行:

make all --trace -d 2>&1 | add_ts.bat "Hello World"

给它一个命令行参数并:

make all --trace -d 2>&1 | add_ts.bat Hello World

如果给它两个命令行参数,第二个将被忽略。但无论如何,它不会读取标准输入,因此对其进行管道处理是徒劳的。

网站ss64.com非常好地介绍了CMD重定向和管道,但它假设您知道一个程序必须执行哪些操作才能成为可管道的命令:作为上游命令,它必须写入其标准输出;作为下游命令,它必须读取其标准输入。


你能解释一下为什么我的原始批处理文件不起作用吗?我想这可能与 STDOUT 和 STDERR 缓冲有关。 - Bob
@Adrian 当批处理文件运行时,它将%1替换为第一个命令行参数,以此类推,然后执行其逻辑并结束。将其输入进行管道传输并不能使其用第一整个STDIN行替换%1,然后为每个后续行重新运行自身。您的add_ts.bat未传递任何命令行参数,并且没有读取其STDIN的代码,无论是通过管道还是其他方式,因此它只打印了一次时间并停止了。 - Mike Kinghan
我不明白的是为什么|本身不足以将STDOUT和STDERR发送到add_ts.bat的STDIN。ss64.com对我理解如何/为什么有帮助吗? - Bob
@Adrian 请在回答中查看更多解释。 - Mike Kinghan
1
我刚刚使用脚本为我的命令行应用程序的标准输出添加了时间戳。该应用程序通常会连续运行数十分钟,但是在重定向的结果中,时间戳都相同,与我的预期不符。我是否误解了脚本的预期用法? - Gang YIN

0

如果您不介意额外的开销,使用批处理文件包装器是一个聪明的解决方案。否则,我认为您将不得不修改GNU make本身以使其打印出这些数据。

如果由于某种原因而无法接受上述方法,则可以使用ElectricMake获取该信息,它是一个GNU-make兼容的make实现,包括许多增强功能,包括带有每个构建作业微秒分辨率时间戳的注释构建日志。ElectricMake是ElectricAccelerator Huddle的一部分。

以下是一个微不足道的“echo Hello World!”作业的注释片段:

<job id="J00007fb820002000" thread="7fb82f7fe700" start="3" end="4" type="rule" name="all" file="
Makefile" line="1">
<command line="2">
<argv>echo Hello, world!</argv>
<output src="prog">Hello, world!
</output>
</command>
<commitTimes start="0.291693" wait="0.296587" commit="0.296628" write="0.296680"/>
<timing invoked="0.291403" completed="0.296544" node="ecdroid3a-59"/>
</job>

<timing>标签显示了相对于构建开始时间的作业的开始时间(0.291403秒)和结束时间(0.296544秒)。

这些带注释的构建日志可以使用ElectricInsight进行图形查看和分析,这是ElectricMake的伴侣工具。

ElectricAccelerator Huddle是ElectricAccelerator的免费版本--在某个点之前完全免费使用,超出该点则需要支付适度的按需费用。

免责声明:我是ElectricAccelerator的架构师。


emake 能够正常工作,但是我的公司不想与之绑定,因为 ECloud 可能会随意将其变为非免费或者甚至停止支持。我和你们的销售代表谈过,他们说免费版本必须每三个月更新一次许可证。如果因为它正在侵蚀你们的企业销售而被停止支持怎么办?你能解决这些问题吗? - Bob
@Adrian ElectricAccelerator Huddle是一款“免费增值”产品,这意味着它既有免费组件,也有付费组件,可以提供额外的功能。 - Eric Melski
我知道,但你仍然没有解释为什么“免费”版本被限制得如此严格,即需要每三个月更新许可证。 - Bob
@Adrian,你误解了。Huddle中的免费功能始终是免费的。也就是说,永远免费,您可以使用Huddle来运行可靠的并行构建,使用高达四个本地代理。您还可以获得注释的构建日志。许可证管理付费功能,该功能允许使用超过四个本地代理以及来自其他主机的无限代理。从技术上讲,在Huddle处于beta版时,该扩展功能也是免费的,并受3个月许可证的管理。在到期后,您仍然可以使用始终免费的部分。 - Eric Melski
@Adrian 我已经要求我们的人通过电子邮件与您联系。 - Eric Melski
显示剩余2条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接