倒转std :: cout返回到行首

问题描述 投票:24回答:4

我正在为Mac OS X编写一个命令行工具,该工具可以处理大量文件。我想向用户显示当前正在处理的文件,但不希望有成千上万个文件污染终端窗口。

相反,我想使用一行来输出文件路径,然后将该行重用于下一个文件。是否有字符(或其他代码)输出到std::cout以完成此操作?

此外,如果我想针对Windows重新定位此工具,两个平台的解决方案是否相同?

c++ macos terminal stdout output-formatting
4个回答
25
投票

“ \ r”对于Windows和Mac OS X均适用。

类似:

std::cout << "will not see this\rwill see this" << std::flush;
std::cout << std::endl; // all done

2
投票

我没有访问Mac的权限,但是从纯控制台的角度来看,这将很大程度上取决于它如何处理回车符和换行符。如果可以从字面上将一个或另一个发送到控制台,则要发送just回车。

[我很确定Mac与* nix和windows区别对待回车符和换行符。

[如果您要就地更新(例如覆盖当前行),建议您查看curses库。这应该提供独立于平台的方式来完成您要寻找的东西。 (因为,即使使用标准C ++,也没有平台独立的方法来满足您的要求)。


0
投票

正如Nathan Ernst的回答所说,如果您想要一种健壮,正确的方法来执行此操作,请使用curses-特别是ncurses

[如果您希望使用省力的hacker方式来工作,请继续...

用于Linux,UNIX,MacOS,Windows等的命令行终端倾向于支持一小组基本的ASCII控制字符,包括十进制字符13-称为回车符,而encoded in C++则为'\ r'或等价于八进制'\ 015'或十六进制'\ x0D'-指示终端返回到行首。

您通常想做的是...

int line_width = getenv("COLUMNS") ? atoi(getenv("COLUMNS")) : 80;
std::string spaces{line_width - 1, ' '};
for (const auto& filename : filenames) {
    std::cout << '\r' << spaces << '\r' << filename << std::flush;
    process_file(filename);
}
std::cout << std::endl; // move past last filename...

[这将使用一串空格在写入下一个文件名之前覆盖旧文件名,因此,如果文件名较短,则看不到较早的文件名中的尾随字符。

std::flush确保C ++程序在开始处理文件之前,先调用OS std::flush函数将文本发送到终端。否则,更新所需的文本-write(),空格,\r和文件名-将添加到缓冲区中,仅写入OS-例如。 4k块-缓冲区已满时,因此显示的文件名将使数十个文件滞后于正在处理的实际文件。此外,假设缓冲区为4k-4096字节-有时您要缓冲4080字节,然后输出下一个文件名的文本:您将以\r和15个空格填充缓冲区,当自动-刷新将最终清除屏幕上该行的前15个字符,并保留前一个文件名的其余部分(如果长度超过15个字符),然后等待直到缓冲区满为止再更新屏幕(仍然是偶然的) 。

最后的\r只是将光标从您一直在打印文件名的那一行上移到上面,因此您可以编写“全部完成”,或者只留下std::endl并让shell提示符显示在干净的一行上,而不是可能会覆盖您的最后一个文件名的一部分(像zsh这样的大shell对此进行检查)。


-2
投票

std :: cout将“ \ r”解释为返回行的开头,如果您不想每次都添加“ << endl”,请使用“ \ n”

main()

© www.soinside.com 2019 - 2024. All rights reserved.