在 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
参数。 (%b
s 是\
转义字符串,%s
代表标准字符串。)
其他的是'\e[0;35m'
、'$ '
和'\e[00m'
,分别对应格式中的%b
、%s
和。%b
我在这里放置\e
s,因为它们逃脱了[
前面的大括号。