Как откатить строки из cout? - PullRequest
9 голосов
/ 19 июля 2010

Я кодирую мониторинг задач, который обновляет ход выполнения задач, используя cout. Я хотел бы отображать один ход выполнения задачи на строку, поэтому мне нужно откатить несколько строк консоли.

Я настаиваю на «нескольких», потому что \b выполняет работу за одну строку, но не стирает \n между строк.

Я пытался std::cout.seekp(std::cout.tellp() - str.length());, но tellp() возвращает -1 (ошибка).

Ответы [ 5 ]

20 голосов
/ 19 июля 2010

Вы можете сделать cout << '\r';, чтобы перейти к началу текущей строки, но перемещение вверх зависит от системы.Для Unix смотрите man termcap и man terminfo (и ищите cursor_up).На ANSI-совместимых терминалах (таких как большинство современных терминалов, доступных в Unix) это работает, чтобы двигаться вверх: cout << "\e[A";.

Не пытайтесь искать в cout, большую часть времени это невозможно найти (кромепри перенаправлении в файл).

Как уже упоминалось в других ответах, использование библиотеки ncurses (или slang ) обеспечивает хорошую абстракцию для терминального ввода-вывода в Unix.

Вместо заполнения пробелами (что подвержено ошибкам, поскольку не каждый терминал имеет ширину 80 символов), вы можете сделать \r + clr_eol: std::cout << "\r\e[K" << std::flush.

8 голосов
/ 19 июля 2010

Используйте выходную библиотеку форматирования, такую ​​как ncurses , если можете;это значительно упрощает манипулирование терминалом.

5 голосов
/ 19 июля 2010

Ни C, ни C ++ не определяют ничего подобного.Вам нужно явное манипулирование терминалом.В Unix вы можете использовать curses .Понятия не имею, что там для Windows.

2 голосов
/ 27 июля 2016

Я знаю, что это старый пост, но принятый не охватывает случаи, когда cout передается в программу или файл, и это верхняя часть моих поисков в Google.Следующее будет обрабатывать как поточечный, так и непайпированный стандартный вывод с немного другим поведением.

#include <iostream>
#include <functional>
#include <stdio.h>

#ifdef _WIN32
#include <io.h>
#else
#include <unistd.h>
#define _isatty isatty
#define _fileno fileno
#endif

const std::function<void(const size_t&)> progress_printer(_isatty(_fileno(stdout)) == 1 ?
    [](const size_t& i) {
        std::cout << "\rNumber " << i << std::flush;
    } :
    [](const size_t& i) {
        static std::ios::off_type last(-1);
        if(last != -1)
            std::cout.seekp(last, std::ios::beg);
        last = std::cout.tellp();
        std::cout << "Number " << i << std::endl;
    }
);

Это не проверено в Windows, но должно работатьЧто он делает, так это определяет, является ли файловый дескриптор или tty.Если это так, то он просто пишет '\ r', если позиция не изменилась с момента последней печати или перевода строки.Если это не символ новой строки, он ищет место, которое было последним после печати. ​​

Он ведет себя иначе для файлов, чем для tty.Для файла, если что-то выводится в поток между отпечатками, он может перезаписать часть или все написанное даже после перевода строки.Для ttys он просто перезаписывает символы в начале текущей строки.

0 голосов
/ 31 мая 2018

Надеюсь, это поможет;) [Должно работать в Linux.]

// "\e[0K" Clear line from cursor to the end
cout << "\e[A\r\e[0K"<<what_you_want<<endl;
...