c++ - 乱码的控制台输出管道 stderr 到更多

标签 c++ pipe 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;
        }
    }
}

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

我的代码.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 |更多 也会给出乱码的结果,但 ./mycode>/dev/null |更多 没有。

没有 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 位模式编译为 Release 版本。 我认为这很容易重现并获得相同类型的结果,无论是使用 IDE 还是类似以下内容进行编译: CL/nologo/D WIN32/D_WIN32_WINNT=0x502/EHsc mycode.cpp - 这些标志可能不是全部都需要,因为它是一个如此简单的程序,但恰好包含在我通常用于测试的 bat 文件中.

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

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

最佳答案

从我的评论扩展。您的代码没有什么特别出人意料的。如果你将一个程序的输出通过管道传递给不同的东西,默认情况下只有 stdout 被传递给这个程序。 stderr 仍然只是打印在控制台上。因此,在不重定向到 null 的情况下,程序的 stderr 和 more 的输出将同时打印到控制台,并且不会同步,因为 more 命令是 fork 的(?不太确定,但已经足够了)。由于在管道和输入处理中存在延迟,这将扰乱输出顺序。

通过重定向到 null,您只将 stdout 重定向到 null,您的 more 得到空输入,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,但它会在声明此重定向时重定向它,因为 stdout 正在被定向。

您可能想要第二个变体。

注意:不知道这在 Windows 上如何工作,我使用 arch btw ;-)

关于c++ - 乱码的控制台输出管道 stderr 到更多,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59137264/

相关文章:

bash - 如何同步记录 stderr 和 stdout,但仅将 stderr 打印到屏幕?

c++ - 类中的静态字符串常量与常量的命名空间 [c++]

c++ - 使用指针

Unix FIFO 在吗?

c++ - 如何将 stderr 与输出流相关联

haskell - 忽略进程的标准错误

c++ - 从成员地址推导结构模板类型

c++ - C语言的Windows UIAutomatin

具有非确定性输出的 C fork and pipe 程序

c - 基于管道的进程间通信程序