无法使用 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'
在控制台应用程序的开发过程中,我注意到我无法在 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'