据我所知,一个行为良好的命令行程序应该检查$TERM
环境变量,获取终端模拟器的名称,在terminfo
数据库中查找它的条目,然后使用这些转义码来控制终端设置,例如颜色、字体、样式、擦除屏幕和设置光标位置。
然而,我是一个懒惰的程序员,如果我想让一些文本变成绿色,那么到目前为止最简单的方法就是直接在我的程序中嵌入 ANSI 转义码:
print("\033[32mhi\033[0m")
Run Code Online (Sandbox Code Playgroud)
以这种方式更改终端颜色很容易实现,让我不必学习新的依赖项(例如 ncurses),让我免于运行任何外部程序(例如tput
),并让我用任何包含字符串的语言编写程序,而不是任何具有终端库的语言。
我的理想主义者认为依赖标准总是比依赖一个特定的实现要好。我的 macOS 安装在/usr/share/terminfo
. 另一方面,实用主义者注意到每个人都已经嵌入 ANSI 代码多年了,而且一切似乎都很好。
我经常看到避免使用帮助程序库而直接使用 ANSI 代码的代码,或者只检查是否$TERM
有任何其他内容的dumb
软件,或者根本不检查的软件$TERM
。而且我很少看到有人抱怨这个,或者要求支持其他终端类型。
此外,我在互联网上看到很多很多帖子都没有提到任何其他终端类型或转义码,将 ANSI 集称为“如何在终端中使用粗体和颜色”。似乎所有其他转义代码集都已消失,ANSI 代码(或 ECMA-48 代码或 VT102 代码)已成为开发社区已确定的事实上的标准。
所以,我的问题是:如果我在 2019 年编写命令行软件,是否可以假设它仅用于使用 ANSI 的终端?
编辑:人们建议tput
在运行时调用以将颜色打印到屏幕上,而根本无需处理 terminfo。这有效,并且在许多情况下是一个很好的解决方案,但在我看来,它引入了不必要的运行时成本,因为它必须在我的程序启动时多次执行单独的二进制文件。
小智 5
如果我正确理解了这个问题,它真的可以归结为意见吗?下面尝试总结一些值得考虑的点
听起来很琐碎,即使世界上的每个终端都正确理解 ANSI 序列(并非如评论中提到的那样,对于所有的陈述,找到一个反例就足以拒绝该陈述):考虑两个重定向到文件或通过其他程序流水线输出的情况(例如,程序的交互式使用grep
或脚本调用)。
在这些情况下,通常希望能够获得未着色的输出以简化处理。TERM
在这些情况下,完全依赖环境变量仍然是不够的,例如可以交互方式输入管道,这将导致TERM
设置但颜色输出(可能)不受欢迎。
我已经编写了很多脚本,它们只输出独立的原始 ANSI 序列TERM
(通常带有打开/关闭该着色的选项)。对同一个终端模拟器使用不同的终端模拟器、shell 甚至选项,我经常收到不同颜色的输出。很少(但这种情况存在并且都可以在现代 Linux 系统上找到)我还注意到颜色超出了识别范围(例如黑色上的深灰色等)。有时,一些应该只涂成绿色的东西也被应用了“划掉”的效果……
对于“有趣的见解”,请进行任何无条件(即独立于TERM
)使用大量 ANSI 转义序列的测试,然后在: rxvt
、gnome-terminal
、xterm
最后在 Linux 控制台上运行它。
如果不使用抽象层之一,尽管目标应用程序识别并处理了转义序列,但着色总是有可能失败。
在 2019 年,假设原始 ANSI 转义序列将按预期工作并不完全安全。
考虑终端控制对您的应用程序的重要性:如果它很重要(从某种意义上说,它在没有颜色/终端控制的情况下会失去重要的功能),那么原始 ANSI 转义序列出现问题的风险就太高了。如果它不是那么重要(例如,对日志的吸引力,花哨的交互式菜单与简单的交互式菜单等),则采用非常有限的彩色输出抽象(例如原始 ANSI 序列 + 选择所有颜色的选项)似乎是合理的)。
当需要彩色输出或其他终端控制序列的同一个应用程序也需要以特殊方式获取输入时,那么是时候寻求一个彻底开发的解决方案了,比如 ncurses 或更“现代”的东西......
正如评论中所指出的:只有经过测试的环境对于任何软件来说才是真正安全的。如果您了解环境,则总是可以(尽管以一些抽象的“可移植性”为代价)向您的程序添加在该环境中实现的假设。
最后,该方案是实际使用与终端信息的更先进的图书馆是不是安全情况下都可以:颜色与配置的终端配色方案各不相同,像下划线一些效果只是没有适用于所有终端和字体的组合。然后,也有一些情况TERM
是“错误地”设置导致应用程序失败(我在运行时经常遇到问题tmux
over ssh
)。
归档时间: |
|
查看次数: |
1900 次 |
最近记录: |