【问题标题】:Can Terminal.app be made to respect ANSI escape codes?可以让 Terminal.app 尊重 ANSI 转义码吗?
【发布时间】:2014-11-10 19:37:21
【问题描述】:

我注意到,在将TERM 环境变量设置为xtermxterm-256color 时,Mac OS X 的 Terminal.app 实用程序尊重大多数 ANSI 转义码,至少当这些转义码与更改文本颜色有关时。

例如:

echo -e "\033[0;31mERROR:\033[0m It worked"

生产:

不过,我对 ANSI 转义码提供的光标位置操作功能更感兴趣。不幸的是,根据我收集到的信息, 类型的代码在 Terminal.app 中似乎不太好用。例如,我想要做的事情是这样的:

echo -e "\033[sHello world\033[uG'day"

ESC[s 保存当前光标位置,而ESC[u 恢复上次保存的位置。由于运行上面的脚本,我希望“G'day”中的五个字符在光标重新定位后覆盖“Hello”的五个字符,产生以下结果:

G'day world

确实,这正是我使用 iTerm2.app、ConEmu for Windows(运行 MinGW 或 MSYS Git 的 bash.exe 副本)等所得到的。然而,我在 Terminal.app 中看到的是:

Hello worldG'day

除了 Terminal.app 缺乏对这些代码的支持之外,还有其他原因吗?有没有办法启用这个功能?有没有可能我配置错误?我的学期设置?还有什么?

我一直在到处搜索,但没有找到任何与 Terminal.app 相关的东西,特别是。我觉得奇怪的是它会通过 ANSI 转义码支持彩色文本,但不支持通过完全相同的技术重新定位光标。这似乎是一个相当明确的标准的一个相当任意的子集。这就是让我觉得我配置错误的原因,而不是 Terminal.app 是罪魁祸首……但是,我想它可能根本无法完成。 (可能是 iTerm2 存在的原因之一?)

如果有人能对这种情况有所了解,将不胜感激!

更新

所以,我做了更多的阅读和实验,发现了以下奇怪之处:

在查看了下面 n.m. 的回答后,我决定将 tput 返回的字节写到一个文件中,看看它们与常规 ANSI 指令有何不同。

$ echo "$(tput sc)Hello world$(tput rc)G'day" > out.bin
$ cat -e out.bin
^[7Hello world^[8G'day$

如果我将序列ESC 7ESC 8 发送给它,似乎一切都按预期工作,但如果我发送它ESC [sESC [u,则不会,据我了解,这是 ANSI SCP 和 RCP 代码的更典型表示(分别保存光标位置和恢复光标位置)。由于不可能将 ASCII 十进制字符 78 放在转义的八进制字节表示旁边(\0337 != ESC),因此可以使用环境变量来避免依赖 tput

$ esc=$'\033'
$ csi="${esc}["
$ echo "${csi}0;31mERROR:${csi}0m It worked."
ERROR: It worked.  # Color works, as before
$ echo "${csi}sHello world${csi}uG'day"
Hello worldG'day   # No dice
$ echo "${esc}7Hello world${esc}8G'day"
G'day world        # Success

我不确定这是为什么。如果 ESC 7ESC 8 是 ANSI SCP 和 RCP 的某种专有或自定义代码,可能会因终端实现而异,这将向我解释为什么 tput 是首先创建。

不幸的是,我无法将tput 用于我目前的工作,因为我并不是专门在 bash 环境中工作。我更好奇原始字节是如何在终端之间解释的,更具体地说,是否有办法让 Terminal.app 尊重与我所有其他终端模拟器相同的 ANSI 转义码'试过似乎没有问题。这可能吗?在这一点上,我开始认为它可能根本不可能,这很好,但很高兴知道肯定,并且可能还了解原因。

【问题讨论】:

  • 我不在我的 iMac 上,但使用 printf 而不是 echo 和/或 /usr/bin/echo 而不是 shell 的内置 echo 可能值得一试。
  • 我没有/usr/bin/echo,但我确实有/bin/echo,而且printf"\033[sHello world\033[uG'day" 都没有,不幸的是......但是,printf当我分别为 SCP 和 RCP 代码发送 ESC 7ESC 8 而不是 ESC [sESC [u 时,echo 起作用了。我根据这种行为更新了问题。
  • 查看this answer 了解ESC 7ESC 8 工作的原因。

标签: macos terminal iterm2 ansi-escape


【解决方案1】:

不要使用 ANSI 代码。使用适当的基于 terminfo 的技术。未指定基于 Xterm 的终端支持所有 ANSI 代码。有些是为了兼容性,有些则不是。

保存光标位置顺序由tput sc命令给出,恢复光标位置为tput rc

echo -e "$(tput sc)Hello world$(tput rc)G'day"

应该在支持这些序列的任何终端上工作。

要查看受支持序列的可读表示,请使用infocmp 命令。输出可能很长。如果您对scrc 感兴趣:

infocmp | grep --color ' [sr]c='

免责声明:在我的 Linux 机器上测试,附近没有 Mac。

更新

Terminal.app 以 xterm 为模型,xterm 以 VT100 终端为模型。 VT100 没有实现CSI uCSI s 序列,而是使用了DEC 私有ESC 7ESC 8 序列(source)。后来的 VT 型号同时支持 CSI s/uESC 7/8,名称不同,功能略有不同 (source)

ECMA 48 似乎没有指定任何保存/恢复光标位置序列(source (PDF)),或者我在那里找不到它们。我不知道CSU s/u 来自哪里。他们在 VT510 文档中的名字表明他们与 SCO 有某种联系。 This source 表明它们实际上是没有标准含义的私有序列。 SUN 终端使用SCI s 进行复位。将这两个序列标记为 ANSI 可能是错误的。

现代版本的 xterm 和其他 X11 终端程序(konsole、rxvt...)确实支持ESC 7/8CSI s/u,但terminfo 数据库只宣传ESC 7/8。 Terminal.app 显然只支持ESC 7/8

【讨论】:

  • 感谢您的信息!我不知道 tput 或 infocmp 命令,这是好东西。不幸的是,我实际上并没有在纯 bash 环境中工作(尽管这是我的用例之一),所以我认为我不能接受这个作为最终答案。目前,我还在使用 Python 和 C++,并试图弄清楚需要写出哪些字节才能最大限度地与多个终端兼容。到目前为止,他们似乎都表现得如我所料,除了 Terminal.app,这是不幸的......因此我想知道我是否配置错误。
  • 请提出您需要回答的问题。如果您想在 C 和 Python 中操作终端,请询问如何在 C 和 Python 中操作终端。这个问题没有问这样的事情,所以答案中没有提到。它特别提到了 bash 并进行了相应的标记,所以这就是我们所涵盖的内容。
  • tput 可能是在 bash 脚本等中使用的正确工具,但除了进行子进程调用之外,我看不出它对于另一个需要打印到终端并在此过程中正确使用 ANSI 代码。这个问题更多地与 Terminal.app 的预期行为有关,而不是具体如何在 bash 中执行此操作,所以我继续删除了 bash 标记。
  • Unix 标准是 terminfo,而不是 ANSI 代码。每个操纵终端的自尊程序都使用 terminfo。如果您需要知道如何在 C 中执行此操作,请询问如何在 C 中执行此操作
  • 我还不关心如何在特定语言中最好地完成它的实用性。带着这个问题,我试图了解所涉及标准的状态,以及 Terminal.app 的行为如何达到或偏离这些标准。您的更新在这方面提供了很多有用的信息,这正是我正在寻找的那种信息。我很满意现在了解了一些历史,SCP 和 RCP 可能是后来作为某个单独规范的一部分出现的,因此为什么它们似乎并不总是有效。感谢您帮助我研究此问​​题,我会将其标记为答案。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2018-01-15
  • 1970-01-01
  • 2011-05-05
  • 1970-01-01
  • 2011-09-11
  • 2014-08-25
相关资源
最近更新 更多