'Is there a way to erase the last line of output?
A very simple program that prints 3 lines of output:
console.log('a');
console.log('b');
console.log('c');
Is there a way from program to delete the last line after it has been printed?, i.e.
console.log('a');
console.log('b');
console.log('c');
clearLastLine();
console.log('C');
which would produce:
a
b
C
Solution 1:[1]
The simple solution is to not print a newline character (i.e., do not use console.log
).
- Use
process.stdout.write
to print a line without the EOL character. - Use carriage return (
\r
) character to return to the begin of the line. - Use
\e[K
to clear all characters from the cursor position to the end of the line.
Example:
process.stdout.write("000");
process.stdout.write("\n111");
process.stdout.write("\n222");
To this line, the output will be:
000
111
222
However, if you execute:
process.stdout.write("000");
process.stdout.write("\n111");
process.stdout.write("\n222");
process.stdout.write("\r\x1b[K")
process.stdout.write("333");
The output is:
000
111
222\r\x1b[K
333
However, the terminal will display:
000
111
333
Solution 2:[2]
Way 1:
const clearLastLine = () => {
process.stdout.moveCursor(0, -1) // up one line
process.stdout.clearLine(1) // from cursor to end
}
Way 2:
const readline = require('readline')
const clearLastLine = () => {
readline.moveCursor(process.stdout, 0, -1) // up one line
readline.clearLine(process.stdout, 1) // from cursor to end
}
Way 3:
const ESC = '\x1b' // ASCII escape character
const CSI = ESC + '[' // control sequence introducer
const clearLastLine = () => {
process.stdout.write(CSI + 'A') // moves cursor up one line
process.stdout.write(CSI + 'K') // clears from cursor to line end
}
Way 1 uses the methods provided by the built-in tty
module.
Way 2 uses the built-in readline
module.
Way 3 uses ANSI escape sequences.
I learned about ANSI escape sequences by viewing the source code of log-update, which I found out about from dthree's answer. After doing some more research, I learned about the built-in readline
and tty
modules.
By reading the source code of Node.js, I learned that the methods used in way 1 are essentially wrappers around the methods used in way 2 and that the methods used in way 2 are essentially wrappers around the methods used in way 3. So every way ends up doing basically the same thing under the hood. I've ordered the ways from higher-level to lower-level.
I suggest using way 1 over way 2 and way 2 over way 3 mainly because I think that way 1 is less code and more clear (and therefore more readable) than way 2 and that way 2 is less code and more clear (and therefore more readable) than way 3 and that performance improvements (if any) achieved by using a lower-level way are likely negligible. However, I think way 3 avoids loading the built-in readline
module.
This solution (every way) assumes your cursor is at the start of an empty line right before your program calls clearLastLine()
. As Gajus states in his answer, the solution is simpler if instead your cursor is at the end of the last line. So could you use process.stdout.write()
(instead of console.log()
) to print the last line without a trailing newline?
Or the solution is even simpler if you don't need to print the last line in the first place. Is all this tinkering with stdout a code smell? Could you rearchitect your code so that the last line doesn't get printed at all?
In my case I'm testing a helper function I wrote that calls console.error()
, and I don't want the logged error message to show up in my test output. So instead of having my helper function call console.error()
, I could make it throw an error (or just return an error code and/or message or a boolean). And then my main program that calls my helper function could call console.error()
if my helper function throws an error (or returns an an error code and/or message or false
). Or I could pass a boolean flag argument to my helper function that tells it whether or not to log an error. Or I could redirect stderr, or mock the global console
or stub console.error()
, etc.
If you wanted to clear the last three lines written to system.stdout
, you could do:
const clearLastLines = (count) => {
process.stdout.moveCursor(0, -count)
process.stdout.clearScreenDown()
}
clearLastLines(3)
Solution 3:[3]
The following works for me:
process.stdout.clearLine();
process.stdout.cursorTo(0);
Solution 4:[4]
Solution 5:[5]
There's a simple workaround:
process.stdout.write(`\x1Bc\rData left: ${currentPercentage}%`)
That would print something like: "Data left: 100%"... and by using that, you would clear the screen after each iteration.
'\x1Bc' clear the line, and '\r' returns to column 0.
Solution 6:[6]
The only module that worked for me without erasing everything before the progress bar was single-line-log
Install it with:
npm i single-line-log
Import it with:
var log = require('single-line-log').stdout;
Then instead of logging the progress bar with console.log()
, just use log()
:
// OLD:
while (task_is_running) {
console.log(Progress.update())
}
// NEW:
while (task_is_running) {
log(Progress.update())
}
Combined with clui
for the progress bar, this works great.
Solution 7:[7]
Below is an example of the php language, but it is quite general
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 | Maxim |
Solution 2 | ma11hew28 |
Solution 3 | Richard Nienaber |
Solution 4 | dthree |
Solution 5 | mzalazar |
Solution 6 | marsnebulasoup |
Solution 7 | BlackHammer |