使用Swift命令行工具更新当前行

时间:2022-10-22 14:56:10

I built a OS X command line tool in Swift (same problem in Objective-C) for downloading certain files. I am trying to update the command line with download progress. Unfortunately, I cannot prevent the print statement to jump to the next line.

我在Swift中构建了一个OS X命令行工具(Objective-C中的问题),用于下载某些文件。我正在尝试用下载进度更新命令行。不幸的是,我无法阻止print语句跳转到下一行。

According to my research, the carriage return \r should jump to the beginning of the same line (while \n would insert a new line).

根据我的研究,回车r应该跳转到同一行的开头(而n将插入新的行)。

All tests have been performed in the OS X Terminal app, not the Xcode console.

所有测试都在OS X终端应用程序中执行,而不是在Xcode控制台。

let logString = String(format: "%2i%% %.2fM \r", percentage, megaBytes)
print(logString)

Still, the display inserts a new line. How to prevent this?

不过,该显示插入了一条新行。如何预防呢?

2 个解决方案

#1


4  

Your example will only work on the actual command line, not in the debugger console. And you also need to flush stdout for every iteration, like this:

您的示例将只在实际的命令行上工作,而不在调试器控制台。你还需要在每次迭代中刷新stdout,就像这样:

var logString = String(format: "%2i%% %.2fM \r", 10, 5)
print(logString)
fflush(__stdoutp)

#2


4  

Note: This won't work in Xcode's debugger window because it's not a real terminal emulator and doesn't fully support escape sequences. So, to test things, you have to compile it and then manually run it in a Terminal window.

注意:这在Xcode的调试器窗口中不能工作,因为它不是一个真正的终端模拟器,并且不完全支持转义序列。因此,要进行测试,您必须编译它,然后在终端窗口中手动运行它。

\r should work to move to the beginning of the current line in most terminals, but you should also take a look at VT100 Terminal Control Escape Sequences. They work by sending an escape character, \u{1B} in Swift, and then a command. (Warning: they make some pretty ugly string definitions)

在大多数终端中,\r应该移动到当前行的开始部分,但是您也应该查看VT100终端控制转义序列。它们通过发送一个转义字符(以Swift格式)和一个命令来完成。(警告:它们定义了一些非常难看的字符串)

One that you'll probably need is \u{1B}[K which clears the line from the current cursor position to the end. If you don't do this and your progress output varies in length at all, you'll get artifacts left over from previous print statements.

您可能需要的一个是\u{1B}[K,它清除当前游标位置到末尾的行。如果您不这样做,并且您的进度输出在长度上有所变化,您将会得到从以前的打印语句中遗留下来的工件。

Some other useful ones are:

其他一些有用的是:

  • Move to any (x, y) position: \u{1B}[\(y);\(x)H Note: x and y are Ints inserted with string interpolation.
  • 移动到任意(x, y)位置:只\u{1B}[\(y);只\(x)H注:x和y插入字符串内插。
  • Save cursor state and position: \u{1B}7
  • 保存光标状态和位置:\u{1B}7。
  • Restore cursor state and position: \u{1B}8
  • 恢复光标状态和位置:\u{1B}8
  • Clear screen: \u{1B}[2J
  • 清除屏幕:\ u b { 1 }[2 j

You can also do interesting things like set text foreground and background colors.

您还可以做一些有趣的事情,比如设置文本前景和背景颜色。

If for some reason you can't get \r to work, you could work around it by saving the cursor state/position just before you print your logString and then restoring it after:

如果由于某种原因你不能使用\r,你可以在打印日志字符串之前保存光标状态/位置,然后在以下情况下恢复:

let logString = String(format: "\u{1B}7%2i%% %.2fM \u{1B}8", percentage, megaBytes)
print(logString)

Or by moving to a pre-defined (x, y) position, before printing it:

或移到预先定义的位置(x, y),在打印之前:

let x = 0
let y = 1 // Rows typically start at 1 not 0, but it depends on the terminal and shell
let logString = String(format: "\u{1B}[\(y);\(x)H%2i%% %.2fM ", percentage, megaBytes)
print(logString)

#1


4  

Your example will only work on the actual command line, not in the debugger console. And you also need to flush stdout for every iteration, like this:

您的示例将只在实际的命令行上工作,而不在调试器控制台。你还需要在每次迭代中刷新stdout,就像这样:

var logString = String(format: "%2i%% %.2fM \r", 10, 5)
print(logString)
fflush(__stdoutp)

#2


4  

Note: This won't work in Xcode's debugger window because it's not a real terminal emulator and doesn't fully support escape sequences. So, to test things, you have to compile it and then manually run it in a Terminal window.

注意:这在Xcode的调试器窗口中不能工作,因为它不是一个真正的终端模拟器,并且不完全支持转义序列。因此,要进行测试,您必须编译它,然后在终端窗口中手动运行它。

\r should work to move to the beginning of the current line in most terminals, but you should also take a look at VT100 Terminal Control Escape Sequences. They work by sending an escape character, \u{1B} in Swift, and then a command. (Warning: they make some pretty ugly string definitions)

在大多数终端中,\r应该移动到当前行的开始部分,但是您也应该查看VT100终端控制转义序列。它们通过发送一个转义字符(以Swift格式)和一个命令来完成。(警告:它们定义了一些非常难看的字符串)

One that you'll probably need is \u{1B}[K which clears the line from the current cursor position to the end. If you don't do this and your progress output varies in length at all, you'll get artifacts left over from previous print statements.

您可能需要的一个是\u{1B}[K,它清除当前游标位置到末尾的行。如果您不这样做,并且您的进度输出在长度上有所变化,您将会得到从以前的打印语句中遗留下来的工件。

Some other useful ones are:

其他一些有用的是:

  • Move to any (x, y) position: \u{1B}[\(y);\(x)H Note: x and y are Ints inserted with string interpolation.
  • 移动到任意(x, y)位置:只\u{1B}[\(y);只\(x)H注:x和y插入字符串内插。
  • Save cursor state and position: \u{1B}7
  • 保存光标状态和位置:\u{1B}7。
  • Restore cursor state and position: \u{1B}8
  • 恢复光标状态和位置:\u{1B}8
  • Clear screen: \u{1B}[2J
  • 清除屏幕:\ u b { 1 }[2 j

You can also do interesting things like set text foreground and background colors.

您还可以做一些有趣的事情,比如设置文本前景和背景颜色。

If for some reason you can't get \r to work, you could work around it by saving the cursor state/position just before you print your logString and then restoring it after:

如果由于某种原因你不能使用\r,你可以在打印日志字符串之前保存光标状态/位置,然后在以下情况下恢复:

let logString = String(format: "\u{1B}7%2i%% %.2fM \u{1B}8", percentage, megaBytes)
print(logString)

Or by moving to a pre-defined (x, y) position, before printing it:

或移到预先定义的位置(x, y),在打印之前:

let x = 0
let y = 1 // Rows typically start at 1 not 0, but it depends on the terminal and shell
let logString = String(format: "\u{1B}[\(y);\(x)H%2i%% %.2fM ", percentage, megaBytes)
print(logString)