在控制台应用程序的开发过程中,我注意到我无法将其输出传输到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 将数据通过管道传输到外部程序(然后总是文本)时,它意外地不会表现出通常的流式处理行为。
也就是说,Windows PowerShell 不会在生成原始命令的行(字符串化对象)时传递它们,而是尝试先将它们全部收集到内存中,然后再将它们管道传输到外部程序。
在您的情况下,由于第一个程序永远不会停止生成输出,因此 Windows PowerShell 引擎永远不会停止等待收集所有输出,因此实际上会挂起(直到它最终耗尽内存) - 目标程序甚至永远不会启动,因为这只会在收集输出完成后发生。
解决方法:
-
如果可行,请切换到PowerShell [Core] 7+,其中已删除此限制。
-
在 Windows PowerShell 中,通过
cmd.exe
调用管道,正如你所观察到的,它确实表现出预期的流式处理行为。# Workaround via cmd.exe cmd /c '.but-why.exe print | .but-why.exe read'