我的问题:

我的问题:

在 bash 中,当这些序列来自外部进程或函数的标准输出时,如何将零宽度序列编码到 PS1 中?如何实现writes-prompt-sequences-to-stdout才能在提示中发出多色文本?

PS1='$( writes-prompt-sequences-to-stdout )'


我知道,在编写 bash PS1 提示符时,我必须将零宽度序列包装起来,\[ \]以便 bash 可以计算正确的提示符宽度。

PS1='\[\e[0;35m\]$ \[\e[00m\]'bash 不打印\[ \]并理解提示符只有 2 个字符宽。

如何将这些序列移至外部函数中?以下内容不起作用,我的提示看起来像\[\]$ \[\],即使我可以运行render-prompt并看到它将正确的字节序列写入标准输出。

PS1='$( render-prompt )'
function render-prompt {
    printf '\[\e[0;35m\]$ \[\e[00m\]'
}

将 printf 调用移至 PS1工作:

PS1='$( printf '"'"'\[\e[0;35m\]$ \[\e[00m\]'"'"' )'

我推测,也许 bash 正在扫描 PS1 字符串执行前计算零宽度字节的数量。所以我尝试通过编码未打印的 [] 序列来欺骗它,但它正确地忽略了这个技巧。

PS1='$( printf '"'"'$$$$$'"'"' '"'"'\[\e[00m\]'"'"' )'

我的问题:

如何\[ \]从通过 PS1 调用的函数或二进制文件将序列写入标准输出?

答案1

我想到了。PS1 中的Bash 特殊情况\e\[、 和。\]它转换\e为转义字节、转换\[1字节、转换\]2字节。外部命令必须将字节写入1标准2输出。

根据 ASCII,它们对“标题开始”和“文本开始”进行编码。

http://www.columbia.edu/kermit/ascii.html

这是一个工作示例,它依赖于 printf 将\第一个位置参数中的转义符转换为正确的字节:

PS1='$( render-prompt )'
function render-prompt {
  printf '\1\033[0;35m\2$ \1\033[00m\2'
}
render-prompt | hexdump -C
00000000  01 1b 5b 30 3b 33 35 6d  02 24 20 01 1b 5b 30 30  |..[0;35m.$ ..[00|
00000010  6d 02                                             |m.|
00000012

答案2

你正确地算出了\1,\2\e。但有一种更好、更正确的方法来生成序列。

printf命令将 FORMAT 作为第一个参数。此格式使用后续参数。所以你的函数可以更好地这样写:

render-prompt () { printf "\1%b\2%s\1%b\2" '\e[0;35m' '$ ' '\e[00m'; }

第一个参数是"\1%b\2%s\1%b\2",这就是格式。对于\1和来说,这是一个很好且符合逻辑的位置\2,它包含%b参数。 (%bs 是\转义字符串,%s代表标准字符串。)

其他的是'\e[0;35m''$ ''\e[00m',分别对应格式中的%b%s和。%b我在这里放置\es,因为它们逃脱了[前面的大括号。

相关内容