when someone abandons you,it is him that gets loss because he lost someone who truly loves him but you just lost one who doesn’t love you.
在开始探索之前,还是得再次夸一夸 Arch 的 wiki,虽然自己日常用的是 macOS 和 debian,但是好几次终端有关的问题,却都是通过 Arch 的 wiki 找到了我想要的答案,这次,兜兜转转,也还是让它又出了一份力
本文围绕的东西有:PS1、PS2、PS3、PS4、PROMOTE_COMMAND、ANSI escape code
Bash 有四个可以定制的提示符:
PS1 是在每个命令前都显示的主要提示符,大部分用户都是定制这个值
PS2 命令需要输入时的第二提示符(比如多行命令)
1 | # 修改 PS2 前,"> " 作为默认提示符 |
PS3 不常用,Bash 的内置 select 显示交互菜单时使用. 和其它提示符不一样,它不扩展 Bash escape sequences. 通常在使用包含 select 的脚本时会需要定制此提示符
1 | # 一个带 select 的例子 |
PS4 也不常用,在调试 bash 脚本时显示缩进级别。第一个字符的重复次数表示缩进级别
1 | # 一个带调试的例子 |
而 PROMPT_COMMAND 则是作为一个普通的 bash 命令执行的,只是执行时间是在 bash 显示 prompt 之前
设置 PS1 的时候,用到了 '\[\e]0;\u: \w\a\]\[\e[33;1m\]\u:\[\e[32;1m\]\w\$ ',这次,暂时先不看 OSC 转义序列,看 \[\e[33;1m\]\u:\[\e[32;1m\]
为啥有 \[ 和 \]
不难发现,两端颜色转义序列的两边都有 \[ 和 \],这是为啥呢? 参看 1 2
因为 \e[33;1m 是不可打印字符,而 \[ \] 有助于 Bash 忽略不可打印字符,以便正确计算提示符的大小,如果没有 \[ \],bash 会认为构成颜色代码的转义序列的字节实际上会占用屏幕上的空间,导致 readline 无法知道光标的实际位置,可能会导致提示符被覆盖等奇奇怪怪的问题
但是别高兴的太早,\[ 和 \] 的坏心眼儿
知道了上面 \[ 和 \] 的作用,为了让 PS1 根据不同的场景显示不同的颜色,是不是可以直接用写个函数,通过 echo -e 设置动态的 PS1 了?
如果你是这么想的,那你就正好落入了 \[ \] 的坑,事实上,\[ \] 除了直接对 PS 系列变量设置时有效,对于其他采用输出方式设置 PS 系列变量的情境下都不生效(例如 printf or echo -e)
这时候,就需要用 \001、\002 替换 \[、\]
举个例子:
1 | # this function runs when the prompt is displayed |
再举个例子:
1 | $ PS1='\[\e[32;1m\]\u:\[\e[0m\] ' |
\[、\] 替换成 \001、\002 的原因
readline 接受 \001 和 \002 (ASCII SOH and STX) 作为不可打印的文本分隔符,所以只要用 readline 这个库,就支持这个分隔符
bash 源码中 lib/readline/display.c:
1 | /* Current implementation: |
be slow to promise and quick to perform.