无法使用 PowerShell 传输控制台应用程序的无限输出

Unable to pipe infinite output of console app using PowerShell

在控制台应用程序的开发过程中,我注意到我无法在 PowerShell 中将其输出通过管道传输到自身。

我创建了一个像这样工作的小复制(下面的来源):

PS> .\but-why.exe print # continuously prints a random number every 500 ms
1746112985
1700785785
331650882
...
PS> .\but-why.exe read # echoes stdin
foo                    # this was typed
read 'foo'
bar                    # this too
read 'bar'
PS> "foo","bar" | .\but-why.exe read
read 'foo'
read 'bar'

但是当我尝试将 print 的输出输入 read 时,什么也没有发生:

PS> .\but-why.exe print | .\but-why.exe read

当我将所有输出重定向到成功流时相同:

PS> .\but-why.exe print *>&1 | .\but-why.exe read

但是,当我使用 CMD 时,一切正常:

CMD> but-why.exe print | but-why.exe read
read '317394436'
read '1828759797'
read '767777814'
...

通过调试我发现第二个实例.\but-why.exe read似乎从未启动过。

也许这是我相当旧的 PS 版本?

PS> $host.Version

Major  Minor  Build  Revision
-----  -----  -----  --------
5      1      19041  610

控制台应用的来源(net5.0):

using System;
using System.Threading;

switch (args[0]) {
    case "print": Print(); break;
    case "read": Read(); break;
}

void Print() {
    var rng = new Random();
    while (true) {
        Console.WriteLine(rng.Next());
        Thread.Sleep(500);
    }
}

void Read() {
    string? text;
    while ((text = Console.ReadLine()) != null) {
        Console.WriteLine($"read '{text}'");
    }
}

您在 Windows PowerShell 中发现了一个设计限制已在跨平台 PowerShell [Core] 7+ 版本中修复:

当 Windows PowerShell 将数据 传输到外部程序时 (然后总是 text), 它意外地没有表现出通常的行为。

也就是说,在 正在生成 时,Windows PowerShell 不会在 上传递原始命令行(字符串化对象),而是尝试 首先将它们全部收集在内存中,然后再将它们传输到外部程序。

在你的例子中,因为第一个程序永远不会停止产生输出,所以 Windows PowerShell 引擎永远不会停止等待 all 输出被收集 因此有效地 挂起 (直到它最终耗尽内存) - 目标程序甚至从未启动,因为那只发生在 after 收集输出已完成。


解决方法

  • 如果可行,切换到 PowerShell [Core] 7+,此限制已被删除。

  • 在 Windows PowerShell 中,通过 cmd.exe 调用您的管道,正如您观察到的那样,它确实表现出预期的流式传输行为。

    # Workaround via cmd.exe
    cmd /c '.\but-why.exe print | .\but-why.exe read'