有没有办法擦除输出的最后一行?

问题描述 投票:0回答:6

一个打印 3 行输出的非常简单的程序:

console.log('a');
console.log('b');
console.log('c');

程序是否有办法在打印后删除最后一行?即

console.log('a');
console.log('b');
console.log('c');
clearLastLine();
console.log('C');

会产生:

a
b
C
node.js command-line-interface ansi-escape
6个回答
38
投票

简单的解决方案是不打印换行符(即不要使用

console.log
)。

  • 使用
    process.stdout.write
    打印没有 EOL 字符的行。
  • 使用回车符(
    \r
    )返回行首
  • 使用
    \e[K
    清除从光标位置到行尾的所有字符。

例子:

process.stdout.write("000");
process.stdout.write("\n111");
process.stdout.write("\n222");

到这一行,输出将是:

000
111
222

但是,如果你执行:

process.stdout.write("000");
process.stdout.write("\n111");
process.stdout.write("\n222");
process.stdout.write("\r\x1b[K")
process.stdout.write("333");

输出为:

000
111
222\r\x1b[K
333

但是终端会显示:

000
111
333

32
投票

方式一:

const clearLastLine = () => {
  process.stdout.moveCursor(0, -1) // up one line
  process.stdout.clearLine(1) // from cursor to end
}

方式二:

const readline = require('readline')

const clearLastLine = () => {
  readline.moveCursor(process.stdout, 0, -1) // up one line
  readline.clearLine(process.stdout, 1) // from cursor to end
}

方式三:

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
}

方式一使用内置

tty
模块提供的方法

方式2使用内置的

readline
模块。

方式 3 使用 ANSI 转义序列.

我通过查看log-update的源代码了解了ANSI转义序列,这是我从dthreeanswer中找到的。在做了更多研究之后,我了解了内置的

readline
tty
模块。

通过阅读Node.js的源码,我了解到方式1中使用的方法本质上是对方式2中使用的方法的包装,而方式2中使用的方法本质上是对方式3中使用的方法的包装. 所以每一种方式最终都会在引擎盖下做基本相同的事情。我已经从高级到低级排序了。

我建议使用方式 1 而不是方式 2 和方式 2 而不是方式 3 主要是因为我认为方式 1 比方式 2 代码更少且更清晰(因此更具可读性),而方式 2 代码更少且更清晰(因此比方法 3 更具可读性),并且通过使用较低级别的方法实现的性能改进(如果有的话)可能可以忽略不计。但是,我认为方式3避免加载内置

readline
模块。

此解决方案(无论哪种方式)都假设您的光标在程序调用之前就位于空行的开头

clearLastLine()
。正如 Gajushis answer 中所述,如果您的光标位于最后一行的末尾,则解决方案会更简单。那么,您可以使用
process.stdout.write()
(而不是
console.log()
)来打印没有尾随换行符的最后一行吗?

或者如果您不需要首先打印最后一行,解决方案会更简单。所有这些对 stdout 的修补都是 code smell 吗?你能重新设计你的代码,让最后一行完全不打印吗?

在我的例子中,我正在测试我编写的调用

console.error()
的辅助函数,我不希望记录的错误消息显示在我的测试输出中。因此,我可以让它抛出一个错误(或者只返回一个错误代码和/或消息或一个布尔值),而不是让我的辅助函数调用
console.error()
。然后,如果我的辅助函数抛出错误(或返回错误代码和/或消息或 console.error()
),调用辅助函数的主程序可以调用 
false
。或者我可以将一个布尔值 flag argument 传递给我的辅助函数,告诉它是否记录错误。或者我可以重定向 stderr,或 mock 全局 
console
stub
console.error()

如果你想清除写给

system.stdout
的最后三行,你可以这样做:

const clearLastLines = (count) => {
  process.stdout.moveCursor(0, -count)
  process.stdout.clearScreenDown()
}

clearLastLines(3)

15
投票

以下对我有用:

process.stdout.clearLine();
process.stdout.cursorTo(0); 

2
投票

您可以使用

logUpdate
NPM 模块,或
vorpal
NPM 模块。这些都是这样做的。


1
投票

在进度条之前没有删除所有内容的唯一对我有用的模块是

single-line-log

安装它:

npm i single-line-log

导入:

var log = require('single-line-log').stdout;

然后不要使用

console.log()
记录进度条,只需使用
log()
:

// OLD:
while (task_is_running) {
    console.log(Progress.update())
}

// NEW:
while (task_is_running) {
    log(Progress.update())
}

结合进度条的

clui
,效果很好。


0
投票

有一个简单的解决方法:

process.stdout.write(`\x1Bc\rData left: ${currentPercentage}%`)

那会打印出类似的东西: “剩余数据:100%”......通过使用它,您将在每次迭代后清除屏幕。

'\x1Bc' 清除行,然后 ' ' 返回到第 0 列。

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