可以使Terminal.app遵守ANSI转义码吗?

Mar*_* G. 23 macos terminal ansi-escape iterm2

我注意到,与TERM设置为环境变量xterm或者xterm-256color是Mac OS X的Terminal.app实用尊重大多数ANSI转义码,当为至少那些转义代码涉及到更改文本颜色.

例如:

echo -e "\033[0;31mERROR:\033[0m It worked"
Run Code Online (Sandbox Code Playgroud)

生产:

截图

但是,我对ANSI转义码提供的光标位置操作功能更感兴趣.不幸的是,这种类型的代码在Terminal.app中似乎没有太好用,我已经能够收集到了.例如,我想要做的是这样的事情:

echo -e "\033[sHello world\033[uG'day"
Run Code Online (Sandbox Code Playgroud)

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

G'day world
Run Code Online (Sandbox Code Playgroud)

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

Hello worldG'day
Run Code Online (Sandbox Code Playgroud)

有没有理由这样做,除了Terminal.app之外,只是缺乏对这些代码的支持?有没有办法启用此功能?我有可能有错误配置的东西吗?我的TERM设置?别的什么?

我一直在各处搜索,但没有发现任何与Terminal.app相关的内容.我觉得很奇怪它会通过ANSI转义码支持彩色文本,但不会通过完全相同的技术重新定位光标.这似乎是一个相当明确的标准的相当随意的子集.这就是让我觉得我有一些错误配置的东西,而不是说Terminal.app是应该责备的......但是,我认为它可能根本无法完成.(可能是iTerm2首先存在的原因之一?)

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

UPDATE

所以,我做了一些阅读和实验,并发现了以下奇怪之处:

在查看下面的nm答案之后,我决定将返回的字节写出来,tput以查看它们与常规ANSI指令的不同之处.

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

看起来一切正常,如果我把它的序列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
Run Code Online (Sandbox Code Playgroud)

我不确定为什么会这样.如果ESC 7并且ESC 8是ANSI SCP和RCP的某种专有或自定义代码,有可能从终端实现到终端实现不同,它会向我解释为什么tput首先创建.

不幸的是,我无法tput用于我目前的工作,因为我不是专门在bash环境中工作.我更好奇的是如何从终端到终端解释原始字节,更具体地说,是否有办法让Terminal.app遵守我试过的所有其他终端仿真器的相同ANSI转义码似乎没有问题.那可能吗?在这一点上,我开始认为它可能不是,这很好,但是肯定地知道并且可能还要了解其原因会很好.

n. *_* m. 24

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

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

echo -e "$(tput sc)Hello world$(tput rc)G'day"
Run Code Online (Sandbox Code Playgroud)

应该适用于任何支持这些序列的终端.

要查看支持序列的可读表示,请使用该infocmp命令.输出可能很长.如果您对以下内容感兴趣sc并且rc:

infocmp | grep --color ' [sr]c='
Run Code Online (Sandbox Code Playgroud)

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

UPDATE

Terminal.app在xterm和xterm建模在VT100终端之后建模.VT100没有实现CSI uCSI s序列,但使用了DEC private ESC 7ESC 8sequence (source).后来的VT模型支持两者,CSI s/u并且ESC 7/8名称不同,功能略有不同(来源).

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

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

  • 我并不关心它如何在特定语言中做得最好的实用性.有了这个问题,我试图了解所涉及的标准的状态,以及Terminal.app的行为如何满足或偏离这些标准.您的更新在这方面提供了很多有用的信息,而且正是我所寻找的那种信息.我现在知道了一点历史,SCP和RCP可能后来作为一些单独的规范的一部分出现了,所以为什么它们似乎并不总是起作用.感谢您帮助我研究这个问题,我将此作为答案. (3认同)
  • 请问一个你需要回答的问题.如果你想在C和Python中操作终端,请询问在C和Python中操作终端.这个问题没有问这个问题,所以答案中没有提到.它特别提到了bash,并相应地进行了标记,这就是所涵盖的内容. (2认同)
  • `tput` 可能是在 bash 脚本等中使用的正确工具,但是除了进行子进程调用之外,我不知道它对于想要打印到终端并正确执行的另一个程序来说是多么理想这样做时使用 ANSI 代码。这个问题更多地与 Terminal.app 的预期行为有关,而不是具体如何在 bash 中执行此操作,因此我继续删除了 bash 标记。 (2认同)
  • Unix 标准是 terminfo,而不是 ANSI 代码。每个操作终端的自尊程序都使用 terminfo。如果您需要知道如何在 C 中实现,**询问如何在 C 中实现**。 (2认同)