如何读取一个正在运行的进程的标准输出?
How can I read the standard output of an already-running process?

原始链接: https://devblogs.microsoft.com/oldnewthing/20251204-00/?p=111841

用户询问是否可以在进程已经启动后读取其标准输出。答案是否定的。操作系统不允许外部修改进程的标准输出(或其他核心属性,如环境变量),因为程序依赖于这些属性的一致性以正确运行——包括确定如何输出文本(例如,Unicode支持、缓冲)。在进程进行中更改这些设置可能会导致错误并阻止任何输出。 可能的情况是主进程启动一个辅助进程,然后该辅助进程创建一个具有所需输出的控制台进程。解决方案不是稍后拦截输出,而是**从一开始就控制输出**。这意味着重定向辅助进程的标准输出,以便控制台进程继承该重定向,从而允许主进程捕获所需的输出。区分辅助进程的输出和控制台的输出需要识别流中一致的模式。

## 读取正在运行进程的标准输出:一则黑客新闻讨论 一篇最近的博客文章(devblogs.microsoft.com/oldnewthing)引发了黑客新闻关于读取已经运行的进程的标准输出的讨论。虽然博文作者专注于“正确”的方法,但评论者们争论了“hacky”变通方案的实用性和价值。 许多人同意直接在进程启动后重新定义标准输出是困难的,但提出了几种替代方案。这些方案从使用调试器和API监视器(用于逆向工程,特别是针对恶意软件)到更复杂的解决方案,如代码注入或自定义内核模块。 这场讨论凸显了健壮、官方支持的方法与务实、可能不稳定的hack之间的紧张关系。一些人认为,hack在实际软件开发中通常是必要的——例如,用于反作弊系统或云平台修复——即使它们会产生长期的维护负担。另一些人则强调避免在生产代码中使用hack的重要性。 也分享了Linux的解决方案,包括`strace`、`reptyr`和`dtach`。用户还分享了个人经验和脚本,用于捕获输出,例如将`script`与LLM结合用于调试。最终,这场对话强调了开发者在面对具有挑战性的技术问题时所采取的多样化方法。
相关文章

原文

A customer wanted to know if they could read the standard output of an already-running process. They didn’t explain why, but my guess is that their main process launches a helper process (not written by them) to begin some workflow, and eventually that helper process launches a console process, which produces the desired output. But they want their main process to read that output, presumably so they can continue automating the workflow.

Unfortunately, there is no way to read the standard output of an already-running process. Standard handles, like the environment variables and current directory, are properties of the process that are not exposed to outsiders by the system.¹

In particular, programs do not expect these properties to change asynchronously. For example, a program that might check the standard output handle and put up a progress spinner if it is a console but not if it is a pipe or file.

Some programs check whether their standard output handle refers to a console (in which case they will use functions like WriteConsoleW to get Unicode support or Set­Console­Text­Attribute to get colors. Furthermore, the C runtime libraries typically check their standard output handle at startup to see whether it has been redirected to a file. This alters the behavior of standard I/O functions because buffering is enabled for non-interactive standard output. If you could change the standard output handle out from under a program’s nose, it would try using Write­ConsoleW to write to something that isn’t a console any more. The calls would fail, and the program would generate no output at all.

It’s actually worse because it’s not uncommon for programs to call Get­Std­Handle and save the value in a variable, then use that variable to write to standard output instead of calling Get­Std­Handle every time. So even if you managed to change the standard output handle, you’d be too late.

What you have to do is find a way to influence the standard output of the console process at the point it is created. Since the presumed intention is for the output of the child process to be visible to the user, the console process probably inherits its standard output from its parent, so you can get the child to operate with redirected output by redirecting the output of the parent process. You’ll have to figure out how to distinguish the output of the parent from the output of the child, but so too did human beings who ran the helper process manually, so presumably there’s some consistent way of recognizing it.

¹ Of course, that doesn’t stop a program from explicitly exposing a custom mechanism for allowing other processes to manipulate them.

联系我们 contact @ memedata.com