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.
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");
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);
}
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.
You could delete the line using \b
printf("hello");
int i;
for (i=0; i<80; i++)
{
printf("\b");
}
printf("bye");
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.
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;
}
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.
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
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 ;
}
}
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
echo -e "hello\c" ;sleep 1 ; echo -e "\rbye "
What the above command will do :
It will print hello and the cursor will remain at "o" (using \c)
Then it will wait for 1 sec (sleep 1)
Then it will replace hello with bye.(using \r)
NOTE : Using ";", We can run multiple command in a single go.
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 '>'
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;
}
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 +++
Related
I'm writing a program called split.c that takes from the stdin an input.txt file as input and then sends every other word within the input file to stdout and stderr.
My current codes is as follows:
#include <stdio.h>
int main(){
int input;
// keep getting characters until end-of-file
while ((input = fgetc(stdin)) != EOF){
// prints to stdout
fprintf(stdout, "%d", input);
if(input == " ")
printf("\n"); // encounters whitespace so print new line
// prints to stderr
fprintf(stderr, "%d", input);
if(input == " ")
printf("\n"); // encounters whitespace so print new line
}
return 0;
}
In ubuntu I run make then the command ./split < test/input.txt > myout.txt 2> myerr.txt
The expected output should be, for example.
If input.txt has the following: "Is my code working?"
The output should be:
In myout.txt:
"Is
code
In myerr.txt:
my
working?"
Instead I get the following in both files, a huge number:
6511032731101001051181051001179710...............
Any idea was to what may be wrong with the code? Is my thought process wrong? The idea is that it gets the input file, reads each character and then, when a whitespace is found, it prints a new line in stdout, then does the same thing, but now printing to stderr until it reaches EOF.
I'm still learning the in's and out's (pun intended :) ) of using stdin/out/err so I'm not surprised if I'm not coding correctly. Any guidance is appreciated!
You are using the %d specifier that interprets the corresponding argument as a number. You should be using %c to interpret the corresponding argument as a character.
#include <stdio.h>
#include <conio.h>
#define ENTER_KEY '\n'
#define NULL_TERMINATOR '\0'
int main()
{
char name[100], input;
int counter = 0;
while(input != ENTER_KEY)
{
input = getchar();
name[counter] = input;
counter++;
}
counter--;
name[counter] = NULL_TERMINATOR;
printf("%s", name);
return 0;
}
If I write something, it should continuously saved in the name Array. And the counter should go up on every character I enter. But if I press Backspace, it looks like it makes the counter decreased. Because for example if I write "abcdef" and press backspace 3 times and change that to "abcxyz", and then press Enter. It prints "abcxyz".
It depends on the console driver. On most systems (at least Unix-like in line mode and in Windows console), the program does not receive the characters at the moment they are typed but the system prepares a line (up to the newline character) and sends the full line to the program.
In that case, the backspace if often used to edit that console buffer, meaning that the characters erased are actually removed before being handed to the program. So if you type abcdef<backspace><backspace><backspace>xyz<Return> the program will receive the following string: "abcxyz\n".
Beware, in a GUI program or in fullscreen text mode program like emacs or vi, the system is in raw mode (Unix language) and each character is received when it is typed. In that case, the program has to manage the input and erase its own character array when it receives a <backspace>.
Can You Explain Me This Code ....
What Is The Use Of \r In This Program
#include<stdio.h>
void main()
{
printf("This Is \r Amarendra Deo");
}
The \r has no inherit meaning for the C language, but terminals (aka console) can react to this character in different ways. The most common way for terminal is that carriage return sets the cursor at the start of the current line. So when you execute this line, you'll get
Amarendra Deo
Because printf will print This Is and the \r will set the cursor back to the beginning of the line and Amarendra Deo will overwrite whatever has been printed on that line. And since Amarendra Deo is longer than This Is, all you see is
Amarendra Deo
This is for example a very useful trick for when you want to print something
repeatedly on the same line, for example a status message:
for(size_t i = 0; i < 5; ++i)
{
printf("Processing task %d...\r", i+1);
fflush(stdout);
execute_task(i); // can take several seconds to finish
}
In that case you'll see the the Processing task ... text on the same line and it's a nice visual feature for the user. Try executing that for yourself (change the execute_task(i) with sleep(1) or something to make a delay).
I discovered the function read(), but I don't understand everything.
Here is my code:
#include <unistd.h>
#include <stdio.h>
int main(void)
{
char array[10];
int ret;
printf("read : ");
fflush(stdout);
array[sizeof(array) - 1] = '\0';
ret = read(STDIN_FILENO, array, sizeof(array) - 1);
printf("array = %s\n", array);
printf("characters read = %d\n", ret);
//getchar();
return (0);
}
Here is an example of the running program :
$> ./a.out
read : hi guys how are you
array = hi guys h
characters read = 9
$> ow are you
zsh: command not found: ow
$>
Why is it launching a shell command after the end of the program?
I noticed that if I uncomment the getchar() line, this strange behavior disappears. I'd like to understand what is going on, if someone has an idea :)
Your call to read is reading in the first 9 characters of what you've type. Anything else will be left in the input buffer so that when you program exits, your shell will read it instead.
You should check the return value of read so you know how much has been read as it's not guaranteed that it'll be the amount you ask for and also the value returned is used to indicate an error.
The string read in won't be null-terminated either, so you also should use the return value (if positive) to put the NUL character in so that your string is valid.
If you want to read in the whole line, you'll need to put in a loop and identify when there is an end of line character (most likely '\n').
You typed about 20 characters, but you only read 9 characters with read(). Everything after that was left in the terminal driver's input buffer. So when the shell called read() after the program exited, it got the rest of the line, and tried to execute it as a command.
To prevent this, you should keep reading until you get to the end of the line.
I'm doing the exercises in the "C Programming Language" 2nd Edition by Brian W. Kernighan & Dennis M. Ritchie.
Exercise 1.9 confused me. So here it is:
"Write a program to copy its input to output, replacing each string of one more blanks by a single blank".
I puzzled over this. I post my question here because other learners didn't do this exercise the same as I want to do it. Here it is, using - to represent a blank:
Input: ----hello
Output: -hello
But I want this:
Input: ----hello
Output: ----hello
Input: ----
Output: -
So here is my program:
#include <stdio.h>
#include <stdlib.h>
int main()
{
int character; /* input character */
int non_blank = 0; /* is any non blank character */
while ((character = getchar()) != EOF) {
if (character != '\n') {
putchar(character);
if (character != ' ') {
non_blank = 1;
}
}
else {
if (non_blank == 0 ) {
putchar('\b'); /* go to previous line (blabla\n|cursor|) (blabla|cursor|\n) */
putchar('\r'); /* carriage return */
putchar(' '); /* put one space */
putchar('\0'); /* and put the end of line */
}
non_blank = 0;
}
}
return EXIT_SUCCESS;
}
But spaces aren't erased.
Input: ------|\n
Output: -|-----
Here is my experiment with escape sequences:
#include <stdio.h>
#include <stdlib.h>
int main()
{
printf("bbbbbbbbbbbbbbb");
putchar('\b'); /* jump to previous line */
putchar('\r');
putchar('b');
putchar('\0');
return EXIT_SUCCESS;
}
| is a cursor.
Output: b|
But when I'll add the newline character, it doesn't work. How to make it work with newline characters?
The problem with your code is that you are printing the characters as soon as you process them, and you try to erase them once you detect they have to be compressed to one space.
Your approach is valid, but you must know first that \b only makes the cursor to go back one space (without erasing), so the right approach would be to emit \b \b (a backspace, a space to overwrite the character and another backspace to leave the cursor in a correct position)
The other approach is to wait to print anything until we know if the line terminates with a nonblank string or it finishes with only a \n char.
The following code counts the blank characters and manages two states to cope with that. For sure you will be able to follow the code, and I have tried to document it with comments.
#include <stdio.h>
int main()
{
int c;
int state = 0;
int nblanks = 0;
/* read chars up to EOF */
while((c = getchar()) != EOF) {
switch (state) {
case 0: /* no nonblank character read */
switch (c) {
/* accumulate number of blanks to be printed in case
* we see a nonblank char before \n */
case ' ': nblanks++; break;
/* in this case we have seen nblanks before a \n, so
* we have to print only one blank and \n */
case '\n':
puts(" "); /* just one space */
nblanks = 0; /* reset counter */
break;
/* nonblank char */
default:
/* print all the blanks up to here */
printf("%*s%c", nblanks, "", c);
state = 1; /* switch state */
break;
} /* switch */
break;
/* we have read at least a nonblank char, so we must
* echo the line until the end. */
case 1:
if (c == '\n') {
state = 0;
nblanks = 0;
} /* if */
putchar(c);
break;
} /* switch */
} /* while */
} /* main */
It's completely compatible with K&R second edition, so you only have to compile it and run.
Perhaps the most difficult statement to follow is the printf() line in the middle. The asterisk * allows me to specify the width of the field with a printf parameter, and passing an empty string "" allows me to print a string with nblanks spaces. The final %c format is to print the nonblank character just read. This leads to a compact and efficient code.
Last, some wrong ideas you have:
\b only goes back one character in the terminal (one character, not one line). I't only works when printing to a terminal or to a printer. It doesn't work on a file (the file will get the backspaces as normal characters inside)
\r makes the cursor to go to the first display column. This works only on the screen and in a printer. It does not work in a file, where it gets included as a normal character.
\0 Is a character used by C programs to finish character strings (to know where in memory they finish) It is not a special character for an output device, and it does nothing (it is the ASCII NUL character, does nothing on the output terminal)
finally, if you try to follow the \b \b approach on a printer, it will not erase anithing as the space doesn't erase what has already been printed. So then, you have to follow the second approach.
the desired algorithm should be something like:
implement a state machine with two states. NotInSpaces and InSpaces
(with just two states, a boolean would work)
no special treatment for '\n'
set state to NotInSpaces
Loop: (exit loop on EOF)
getchar
if char is space
then if state is NotInSpaces
then set state to InSpaces
output space
endif
else
output char
endif
end Loop:
output '\n' // to force output buffer flush