非打印转义序列:什么时候?

非打印转义序列:什么时候?

最近,我在终端中玩了很多颜色,因此也玩转转义序列。我已经阅读了 Bash 联机帮助页的相关部分以及网络上的许多有用页面。

我已经得到了大部分我想要的东西;例如,漂亮的彩色 Bash 提示符。也就是说,我仍然对何时应该使用(或需要使用)“非打印转义序列”字符感到有些困惑。那些将是\[\]

如果我在定义我的提示时在 PS1 中使用它们,那么我的提示肯定无法正确显示。如果我使用它们,一切都很好。好的。

但是,在 PS1 之外,它们的操作方式似乎并不相同。例如,为了使脚本更具可读性,我定义了一个$RGB_PURPLE通过简单函数设置的变量c8_rgb()。最终结果是该变量包含\[\e[01;38;05;129m\]打开粗体紫色前景色的值。

当我在 PS1 中使用这个变量时,它达到了我的预期。如果我通过printf或使用echo -e它“一半”有效。该命令printf "${RGB_PURPLE}TEST${COLOR_CLR}\n"(其中COLOR_CLR是重置文本属性的转义序列)导致以下显示:\[\]TEST\[\]其中除第一个\[和最后一个之外的所有内容\]都显示为紫色。

为什么有区别?为什么这些括号是打印出来的而不是由终端处理的?我本希望将它们作为提示的一部分打印时与通过其他方式打印时受到相同的对待。我不明白这种变化。

从经验来看,这些角色似乎必须在提示定义中使用,而它们不应该几乎可用于所有其他情况。这使得使用通用函数(如c8_rgb()上面提到的函数)来处理转义序列生成和输出变得困难,因为该函数无法知道其结果是在提示配置中还是在其他地方。

还有一个快速相关的问题:在输出转义序列方面本质上是相同的echo -e吗?printf我通常使用 printf,但是有什么理由偏爱其中一种呢?

谁能解释一下这种明显的细微差别?在终端中使用转义序列(通常仅用于颜色)时,我还应该注意其他奇怪的情况吗?谢谢!

答案1

在 $PS1 中使用非打印字符时需要“非打印转义序列”,因为 bash 需要知道光标的位置,以便在编辑命令行时可以正确更新屏幕。 Bash 通过计算 $PS1 提示符中的字符数来实现这一点,然后这就是光标所在的列号。

但是,如果您将非打印序列放在 $PS1 中,则该计数是错误的,并且如果您编辑命令行,则该行可能会混乱。因此,引入了\[\]标记来指示不应计算所包含的字节。

答案2

我通过使用找到了足够的解决方案八进制整个转义序列,并使用分隔符的 readline 形式。 PS1、echo -e 和 printf 都以这种方式使用完全相同的字符串执行正确的操作。我在 OSX 上的 Bash 4 和 Linux 上的 Bash 3 中对此进行了测试。

我从这里的答案中得到了 \001 和 \002 的想法:https://superuser.com/questions/301353/escape-non-printing-characters-in-a-function-for-a-bash-prompt?rq=1

例子:

$ TextGreen='\001\033[0;32m\002'
$ TextReset='\001\033[0m\002'
$ SomeString="${TextGreen}prompt_stuph${TextReset} \$ "
$ #
$ # now all of the following work as expected
$ #
$ PS1="$SomeString"
$ printf "$SomeString"
$ echo -e "$SomeString"

答案3

类似的␛[01;38;05;129m,其中第一个字符是 ASCII 转义字符 (U+0027),是一个终端转义序列。它指示终端开始以颜色 129 显示粗体、闪烁的文本。\e是转义字符的 bash 语法(inside $'…'、in PS1、inecho -e和 in printf)。

\[\]不是终端转义序列,它们是 bash 提示符转义序列。它们由 bash 解释,而不是发送到终端。它们的目的是告诉 bash 之间的内容是非打印字符,因此提示符的宽度实际上是不在里面的字符数\[…\]。 Bash 需要知道提示符的宽度来计算行编辑器中的光标位置。

\[…\]如果您的函数打算在提示字符串之外使用,则不应输出它。直接在提示字符串中包含\[和。\]

相关内容