Erase the current printed console line
Asked Answered
I

15

105

How can I erase the current printed console line in C? I am working on a Linux system. For example -

printf("hello");
printf("bye");

I want to print bye on the same line in place of hello.

Improbability answered 2/10, 2009 at 9:11 Comment(2)
The ncurses library will probably do this. I don’t know it well enough to provide an answer, but here are links to docs and a related question. This comment is based on Wil Shipley’s answer from 2009, which may be deleted.Luciennelucier
@TomZych ncurses is overkill for a simple task like this.Judie
S
119

You can use VT100 escape codes. Most terminals, including xterm, are VT100 aware. For erasing a line, this is ^[[2K. In C this gives:

printf("\33[2K\r");
Scott answered 2/10, 2009 at 9:33 Comment(8)
This does not reset the cursor to the beginning of the line (in my terminal, at least), so \r is still required. Note that the use of %c is not necessary. Alternative: printf("\33[2K\r");Explosive
Just a little note that ANSI formatting isn't supported in Windows (ANSI escape code). But it's still possible to use printf("\r ");.Radarman
@Radarman That has changed as of Windows 10 update TH2.Stonehenge
it's not working on Windows before Windows 10Hokanson
@LưuVĩnhPhúc - Question ends with: I am working on a linux systemScott
@Scott I'm adding to CocoaBob's comment above. And the linux should be in the tag, not on the question titleHokanson
what is the solution under windows?Weakfish
@Weakfish I am not a Windows expert. You might find anwsers there: How can I update the current line in a C# Windows Console App?Scott
F
73

Some worthwhile subtleties...

\33[2K erases the entire line your cursor is currently on

\033[A moves your cursor up one line, but in the same column i.e. not to the start of the line

\r brings your cursor to the beginning of the line (r is for carriage return N.B. carriage returns do not include a newline so cursor remains on the same line) but does not erase anything

In xterm specifically, I tried the replies mentioned above and the only way I found to erase the line and start again at the beginning is the sequence (from the comment above posted by @Stephan202 as well as @vlp and @mantal) \33[2K\r

On an implementation note, to get it to work properly for example in a countdown scenario since I wasn't using a new line character '\n' at the end of each fprintf(), so I had to fflush() the stream each time (to give you some context, I started xterm using a fork on a linux machine without redirecting stdout, I was just writing to the buffered FILE pointer fdfile with a non-blocking file descriptor I had sitting on the pseudo terminal address which in my case was /dev/pts/21):

fprintf(fdfile, "\33[2K\rT minus %d seconds...", i);
fflush(fdfile);

Note that I used both the \33[2K sequence to erase the line followed by the \r carriage return sequence to reposition the cursor at the beginning of the line. I had to fflush() after each fprintf() because I don't have a new line character at the end '\n'. The same result without needing fflush() would require the additional sequence to go up a line:

fprintf(fdfile, "\033[A\33[2K\rT minus %d seconds...\n", i);

Note that if you have something on the line immediately above the line you want to write on, it will get over-written with the first fprintf(). You would have to leave an extra line above to allow for the first movement up one line:

i = 3;
fprintf(fdfile, "\nText to keep\n");
fprintf(fdfile, "Text to erase****************************\n");
while(i > 0) { // 3 second countdown
    fprintf(fdfile, "\033[A\33[2KT\rT minus %d seconds...\n", i);
    i--;
    sleep(1);
}
Folacin answered 4/2, 2016 at 0:17 Comment(4)
\r is short for "carriage return", not "rewind", and is a relic of good old typewriters, which had separate operations for "move cursor back to first column" (\r) and "advance page to next row" (\n).Gymnasium
\33[2K is a way to go! Best problem solution for me. Also works on Windows ConEmuHemeralopia
For some reason, all these wonderful answers just don't work for me when I run a simple C executable on my MacOS in Terminal (bash, zsh whatever). I get all kinds of strange behaviours, and weird characters (or nothing at all) printed, but never the clear-line-than-print-over-it etc.Orosco
"\033[A moves your cursor up one line, but in the same column i.e. not to the start of the line" I don't think this works, and I don't see the code listed in the referenceExceptionable
A
62

You can use a \r (carriage return) to return the cursor to the beginning of the line:

printf("hello");
printf("\rbye");

This will print bye on the same line. It won't erase the existing characters though, and because bye is shorter than hello, you will end up with byelo. To erase it you can make your new print longer to overwrite the extra characters:

printf("hello");
printf("\rbye  ");

Or, first erase it with a few spaces, then print your new string:

printf("hello");
printf("\r          ");
printf("\rbye");

That will print hello, then go to the beginning of the line and overwrite it with spaces, then go back to the beginning again and print bye.

Asphyxiant answered 2/10, 2009 at 9:14 Comment(1)
"It won't erase the existing characters though, and because bye is shorter than hello, you will end up with byelo." -> Maybe it is platform dependent? Check my answer: https://mcmap.net/q/204056/-erase-the-current-printed-console-linePentobarbital
P
4

You could delete the line using \b

printf("hello");
int i;
for (i=0; i<80; i++)
{
  printf("\b");
}
printf("bye");
Plainspoken answered 2/10, 2009 at 9:24 Comment(2)
Doesn't \b just move the cursor back one character? The characters will still be there. I guess you could do something like "\b \b".Asphyxiant
On my Linux box the line gets deleted. Maybe the behavior is different on other platforms.Plainspoken
M
3

Usually when you have a '\r' at the end of the string, only carriage return is printed without any newline. If you have the following:

printf("fooooo\r");
printf("bar");

the output will be:

barooo

One thing I can suggest (maybe a workaround) is to have a NULL terminated fixed size string that is initialized to all space characters, ending in a '\r' (every time before printing), and then use strcpy to copy your string into it (without the newline), so every subsequent print will overwrite the previous string. Something like this:

char str[MAX_LENGTH];        
// init str to all spaces, NULL terminated with character as '\r'
strcpy(str, my_string);       // copy my_string into str
str[strlen(my_string)] = ' '; // erase null termination char
str[MAX_LENGTH - 1] = '\r';
printf(str);

You can do error checking so that my_string is always atleast one less in length than str, but you get the basic idea.

Mezzo answered 2/10, 2009 at 9:22 Comment(0)
G
2

i iterates through char array words. j keeps track of word length. "\b \b" erases word while backing over line.

#include<stdio.h>

int main()
{
    int i = 0, j = 0;

    char words[] = "Hello Bye";

    while(words[i]!='\0')
    {
        if(words[i] != ' ') {
            printf("%c", words[i]);
        fflush(stdout);
        }
        else {
            //system("ping -n 1 127.0.0.1>NUL");  //For Microsoft OS
            system("sleep 0.25");
            while(j-->0) {
                printf("\b \b");
            }
        }

        i++;
        j++;
    }

printf("\n");                   
return 0;
}
Gadolinite answered 17/2, 2012 at 23:41 Comment(0)
H
2

This script is hardcoded for your example.

#include <stdio.h>

int main ()
{

    //write some input  
    fputs("hello\n",stdout);

    //wait one second to change line above
    sleep(1);

    //remove line
    fputs("\033[A\033[2K",stdout);
    rewind(stdout);

    //write new line
    fputs("bye\n",stdout);

    return 0;
}

Click here for source.

Hardunn answered 14/7, 2015 at 11:17 Comment(0)
L
2

under windows 10 one can use VT100 style by activating the VT100 mode in the current console to use escape sequences as follow :

#include <windows.h>
#include <iostream>

#define ENABLE_VIRTUAL_TERMINAL_PROCESSING 0x0004
#define DISABLE_NEWLINE_AUTO_RETURN  0x0008

int main(){

  // enabling VT100 style in current console
  DWORD l_mode;
  HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
  GetConsoleMode(hStdout,&l_mode)
  SetConsoleMode( hStdout, l_mode |
            ENABLE_VIRTUAL_TERMINAL_PROCESSING |
            DISABLE_NEWLINE_AUTO_RETURN );

  // create a waiting loop with changing text every seconds
  while(true) {
    // erase current line and go to line begining 
    std::cout << "\x1B[2K\r";
    std::cout << "wait a second .";
    Sleep(1);
    std::cout << "\x1B[2K\r";
    std::cout << "wait a second ..";
    Sleep(1);
    std::cout << "\x1B[2K\r";
    std::cout << "wait a second ...";
    Sleep(1);
    std::cout << "\x1B[2K\r";
    std::cout << "wait a second ....";
 }

}

see following link : windows VT100

Leyte answered 19/8, 2019 at 15:49 Comment(0)
B
1

there is a simple trick you can work here but it need preparation before you print, you have to put what ever you wants to print in a variable and then print so you will know the length to remove the string.here is an example.

#include <iostream>
#include <string> //actually this thing is not nessasory in tdm-gcc

using namespace  std;

int main(){

//create string variable

string str="Starting count";

//loop for printing numbers

    for(int i =0;i<=50000;i++){

        //get previous string length and clear it from screen with backspace charactor

        cout << string(str.length(),'\b');

        //create string line

        str="Starting count " +to_string(i);

        //print the new line in same spot

        cout <<str ;
    }

}
Bloodthirsty answered 29/3, 2016 at 7:5 Comment(0)
P
1

use this function to clear n lines in C++

void clear_line(int n) {
    std::string line_up = "\x1b[A";
    std::string line_clear = "\33[2K\r";
    for (int i = 0; i < n; ++i)
        std::cout << line_up << line_clear << std::flush;
}
Previdi answered 18/11, 2022 at 8:9 Comment(0)
L
1
printf("\x1b[1F");

enter image description here

ANSI Cursor Controls here \x1b is escape code and and [#F represents - go to the beginning of # lines up.

Lutestring answered 13/5, 2023 at 14:22 Comment(0)
L
0

Just found this old thread, looking for some kind of escape sequence to blank the actual line.

It's quite funny no one came to the idea (or I have missed it) that printf returns the number of characters written. So just print '\r' + as many blank characters as printf returned and you will exactly blank the previuosly written text.

int BlankBytes(int Bytes)
{
                char strBlankStr[16];

                sprintf(strBlankStr, "\r%%%is\r", Bytes);
                printf(strBlankStr,"");

                return 0;
}

int main(void)
{
                int iBytesWritten;
                double lfSomeDouble = 150.0;

                iBytesWritten = printf("test text %lf", lfSomeDouble);

                BlankBytes(iBytesWritten);

                return 0;
}

As I cant use VT100, it seems I have to stick with that solution

Lemoine answered 1/2, 2018 at 18:0 Comment(0)
R
0
echo -e "hello\c" ;sleep 1 ; echo -e "\rbye  "

What the above command will do :

  1. It will print hello and the cursor will remain at "o" (using \c)

  2. Then it will wait for 1 sec (sleep 1)

  3. Then it will replace hello with bye.(using \r)

NOTE : Using ";", We can run multiple command in a single go.

Redfin answered 30/6, 2019 at 13:2 Comment(1)
This is bash, not CCart
T
0

For me, this code, work well for serial console window with arduino on Tera Term VT console:

SEROUT.print("\e[A\r\n\e[2K");
SEROUT.print('>');

I use '>' because on my console command i type command after '>'

Tifanie answered 2/5, 2022 at 5:43 Comment(0)
P
-1

Others have already answered OP's question. Here is an answer for those wondering why carriage return behaves the way it does on their Linux machine -

The behavior of the carriage return character seems to be platform-dependent.

From section '5.2.2 Character display semantics' of the C11 standard:

\r (carriage return) Moves the active position to the initial position of the current line.

From section '3.86 Carriage-Return Character (< carriage-return>)' of the POSIX standard (https://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap03.html):

A character that in the output stream indicates that printing should start at the beginning of the same physical line in which the carriage-return occurred. It is the character designated by '\r' in the C language. It is unspecified whether this character is the exact sequence transmitted to an output device by the system to accomplish the movement to the beginning of the line.

It does not state whether carriage return is supposed to erase (=> populate with NUL characters) the entire line or not. My guess is that it is NOT supposed to erase.

However, on my Linux machine (tried on both x86_64 and ARM32), what I observed is that the carriage return character moved the cursor to the beginning of the current line and also populated the line with '\0' characters (NUL characters). In order to notice those NUL characters, you might have to call the write system call directly from your code instead of calling via glibc printf.

Let's take the following code snippet as an example:

printf("hello");
printf("\rbye");

Building and running this on beaglebone black (32-bit ARM) bash terminal:

ubuntu@arm:~$ ./a.out 
byeubuntu@arm:~$ 

strace output on write syscall:

bye)               = 9 9hello
+++ exited with 4 +++
Pentobarbital answered 8/7, 2021 at 2:18 Comment(1)
I see no evidence of NUL characters there, and there shouldn't be any.Psyche

© 2022 - 2024 — McMap. All rights reserved.