乱码控制台输出管道 stderr 到更多



有人可以解释为什么我在Windows控制台中运行一个简单的C++程序获得的输出在通过管道传输到more命令时有点乱码。

代码如下:

#include <iostream>
int main()
{
for(int i=101; i<=120; ++i){
std::cerr << "  cerr " << i << std::endl;
if(i%5==0){
std::cout << "  cout " << i << std::endl;
}
}
}

这两个命令都会在前几行之后产生乱码输出。每次运行时的输出都不同。示例如下:

mycode.exe | 更多

...
cerr 117
cerr 118
                                                                                                                          er cout 105
1 cout 110r
1  cout 1159
cerr 120
cout 120

mycode.exe> NUL | 更多

...
cerr 114
cerr 115
6 cerr 11
                                                                                                                           cerr 117
cerr 118
...

请注意,从水平滚动条中可以看到,某些行有很多空格。

在 Linux 上,./mycode | more也给出了乱码结果,但./mycode > /dev/null | more不。

没有more的输出对于Windows和Linux来说都很好:

cerr 101
cerr 102
cerr 103
cerr 104
cerr 105
cout 105
cerr 106
cerr 107
cerr 108
cerr 109
cerr 110
cout 110
cerr 111
cerr 112
cerr 113
cerr 114
cerr 115
cout 115
cerr 116
cerr 117
cerr 118
cerr 119
cerr 120
cout 120

我在Windows 10上使用Visual Studio C++ 2017 Community Edition版本15.7.4。该程序以 64 位模式编译为发布版本。 我认为这很容易重现并获得相同的结果,无论是使用 IDE 还是类似的东西编译:CL /nologo /D WIN32 /D_WIN32_WINNT=0x502 /EHsc mycode.cpp- 这些标志可能不是全部需要的,因为它是如此简单的程序,但恰好包含在我通常用于测试的 bat 文件中。

顺便说一句,使用./mycode | more的 Linux 输出示例并不奇怪,但它看起来有点奇怪:

...
cerr 109
cerr 110
cerr   cout 110
111
cerr 112
cerr 113
cerr 114
cerr 115
cerr   cout 115
116
cerr 117
...

从我的评论扩展。您的代码没有什么真正出乎意料的。如果将程序的输出通过管道传输到其他内容,则默认情况下仅将 stdout 传递给此程序。标准仍然印在控制台上。因此,在不重定向到 null 的情况下,程序的 stderr 和更多内容的输出将同时打印到控制台,并且不会进行时序化,因为 more 命令是分叉的(? 不完全确定,但足够接近(。由于管道和输入处理存在延迟,这将扰乱输出顺序。

通过重定向到 null,您只会将标准输出重定向到 null,并且您的更多内容会获得空输入并将 stderr 打印到控制台,因此应该不会有干扰,您在 Linux 上可以看到。在 Windows 上,似乎更多的输出回车或空输入的类似内容,我不确定,但这也不是真的没有影响。

如果您正在管道并且不希望输出被弄乱,您总是想要的是以下之一:

# Direct stderr to null, only sends stdout to pipe
prog 2>/dev/null | piper
# Direct stderr to stdout, sends both to pipe
prog 2>&1 | piper
# Direct stdout to /dev/null and stderr to stdout, sends just stdout to pipe
prog 2>&1 1>/dev/null | piper

最后一个似乎有点奇怪,因为 ine 会假设它也将 stdout 重定向到 null,但它会重定向它,在声明此重定向时,标准输出正在被定向。

您可能想要第二个变体。

注意:不知道这在窗口上是如何工作的,我使用 arch 顺便说一句 ;-(

最新更新